/*
* Copyright (c) 2001-2007 James Bailie <jimmy@mammothcheese.ca>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * The name of James Bailie may not be used to endorse or promote
* products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DEBUG
#include "lisp.h"
#endif
void stack_push( struct stack *a, void *o )
{
if ( a->free == 0 )
{
a->values = realloc( a->values, sizeof( void * ) * ( a->used + stack_inc ) );
if ( a->values == NULL )
{
fprintf( stderr, "realloc: %s.\n", strerror( errno ));
exit( 1 );
}
a->free = stack_inc;
a->top = &a->values[ a->used - 1 ];
}
if ( a->used )
++a->top;
*a->top = o;
--a->free;
++a->used;
}
struct object *stack_pop( struct stack *a )
{
struct object *ptr;
if ( a->used )
{
ptr = *a->top;
--a->used;
++a->free;
if ( a->used )
--a->top;
return ptr;
}
return NULL;
}
void stack_truncate( struct stack *a, int i )
{
while( i-- )
stack_pop( a );
}
struct object *make_object()
{
if ( reclaimed_objects->used )
return stack_pop( reclaimed_objects );
if ( object_pool_free == 0 )
{
stack_push( object_pool_stack, ( void *)object_pool );
#ifdef DEBUG
fprintf( stderr, "Allocating object pool %d.\n", object_pool_stack->used );
#endif
object_pool = ( struct object *)memory( sizeof( struct object ) * POOL_INC );
object_pool_ptr = object_pool;
object_pool_free = POOL_INC;
}
--object_pool_free;
object_pool_ptr->data.head = object_pool_ptr->next = NULL;
object_pool_ptr->flags = 0;
return object_pool_ptr++;
}
struct atom *make_atom()
{
if ( reclaimed_atoms->used )
return ( struct atom *)stack_pop( reclaimed_atoms );
if ( atom_pool_free == 0 )
{
stack_push( atom_pool_stack, ( void *)atom_pool );
#ifdef DEBUG
fprintf( stderr, "Allocating atom pool %d.\n", atom_pool_stack->used );
#endif
atom_pool = ( struct atom *)memory( sizeof( struct atom ) * POOL_INC );
atom_pool_ptr = atom_pool;
atom_pool_free = POOL_INC;
}
--atom_pool_free;
atom_pool_ptr->syntax = NULL;
atom_pool_ptr->len = 0;
atom_pool_ptr->id = 0;
atom_pool_ptr->flags = 0;
atom_pool_ptr->data.hash = NULL;
return atom_pool_ptr++;
}
int compare_numbers( const void *a, const void *b )
{
return *( int *)a - *( int *)b;
}
int compare_car_numbers( const void *a, const void *b )
{
return number( ( *( struct object **)a )->data.head->data.atom ) -
number( ( *( struct object **)b )->data.head->data.atom );
}
int compare_car_strings( const void *a, const void *b )
{
return strncasecmp(
( *( struct object **)a )->data.head->data.atom->data.string->string,
( *( struct object **)b )->data.head->data.atom->data.string->string,
MIN (
( *( struct object **)a )->data.head->data.atom->data.string->length,
( *( struct object **)b )->data.head->data.atom->data.string->length ) );
}
int compare_strings( const void *a, const void *b )
{
return strncasecmp( ( *( struct lstring **)a )->string,
( *( struct lstring **)b )->string,
MIN( ( *( struct lstring **)a )->length,
( *( struct lstring **)b )->length ));
}
char *expand_tilde( char *name )
{
struct string *s;
char *ptr, *ptr2;
s = make_string();
string_assign( s, name, strlen( name ) );
if (( s->used == 1 && s->str[ 0 ] == '~' ) ||
( s->used >= 2 && s->str[ 0 ] == '~' && s->str[ 1 ] == '/' ))
{
string_erase( s, 0 );
ptr = getenv( "HOME" );
if ( ptr == NULL )
ptr = str_dup( name, strlen( name ));
else
{
ptr2 = ptr;
ptr = &ptr[ strlen( ptr ) ];
while( ptr > ptr2 )
string_prepend( s, *--ptr );
ptr = str_dup( s->str, s->used );
}
}
else if ( s->used > 2 && s->str[ 0 ] == '~' && isalnum( s->str[ 1 ] ))
{
struct string *login;
struct passwd *passwd;
login = make_string();
ptr = &s->str[ 1 ];
while( *ptr && *ptr != '/' )
string_append( login, *ptr++ );
passwd = getpwnam( login->str );
if ( passwd == NULL )
ptr = str_dup( name, strlen( name ));
else
{
string_assign( login, passwd->pw_dir, strlen( passwd->pw_dir ));
while( *ptr )
string_append( login, *ptr++ );
ptr = str_dup( login->str, login->used );
}
string_free( login );
}
else
ptr = str_dup( name, strlen( name ));
string_free( s );
return ptr;
}
struct stack *find_possibilities( char *name )
{
char *d, *e, *w, *ptr;
DIR *dir, *o;
struct dirent *dp;
struct stack *entries;
struct string *s, *t;
int length, result;
regmatch_t matches[ 4 ];
result = regexec( &find_poss_regex, name, 4, matches, 0 );
if ( result )
{
char err[ 80 ];
free( name );
regerror( result, &find_poss_regex, err, sizeof( err ));
fprintf( stderr, "find_possibilities: regexec(): %s\n", err );
return NULL;
}
length = matches[ 0 ].rm_eo - matches[ 0 ].rm_so;
w = memory( length + 1 );
bcopy( &name[ matches[ 0 ].rm_so ], w, length );
w[ length ] = '\0';
length = matches[ 1 ].rm_eo - matches[ 1 ].rm_so;
d = memory( length + 1 );
bcopy( &name[ matches[ 1 ].rm_so ], d, length );
d[ length ] = '\0';
length = matches[ 3 ].rm_eo - matches[ 3 ].rm_so;
e = memory( length + 1 );
bcopy( &name[ matches[ 3 ].rm_so ], e, length );
e[ length ] = '\0';
entries = make_stack();
dir = opendir(( *d == '\0' ? "." : d ));
t = make_string();
if ( dir != NULL )
{
length = strlen( e );
while(( dp = readdir( dir )) != NULL )
{
if ( dp->d_namlen >= length &&
strncmp( e, dp->d_name, length ) == 0 )
{
s = make_string();
string_assign( s, dp->d_name, dp->d_namlen );
stack_push( entries, s );
string_assign( t, d, strlen( d ));
if ( t->used )
string_append( t, '/' );
ptr = dp->d_name;
while( *ptr )
string_append( t, *ptr++ );
if (( o = opendir( t->str )) != NULL )
{
closedir( o );
string_append( s, '/' );
}
}
}
closedir( dir );
}
else
{
dir = opendir( w );
if ( dir != NULL )
{
while(( dp = readdir( dir )) != NULL )
{
s = make_string();
string_assign( s, dp->d_name, dp->d_namlen );
stack_push( entries, s );
string_assign( t, w, strlen( w ));
string_append( t, '/' );
ptr = dp->d_name;
while( *ptr )
string_append( t, *ptr++ );
if (( o = opendir( t->str )) != NULL )
{
closedir( o );
string_append( s, '/' );
}
}
closedir( dir );
}
}
string_free( t );
free( w );
free( d );
free( e );
return entries;
}
struct stack *format_possibilities( struct stack *entries )
{
int i, max = 1, cols, rows, total, column, target, width;
char mask[ 10 ], *line, *ptr;
struct stack *formatted;
struct string *s, *t;
for( i = 0; i < entries->used; ++i )
{
struct string *s;
s = ( struct string *)entries->values[ i ];
if ( s->used > max )
max = s->used;
}
++max;
do_cols( "format_possibilities", NULL );
width = number( ( *( struct object **)stack->top )->data.atom );
stack_pop( stack );
line = memory( width + 1 );
cols = --width / max;
if ( cols == 0 )
cols = 1;
rows = ( entries->used + cols ) / cols;
total = rows * cols;
snprintf( mask, sizeof( mask ), "%%-%ds ", max - 1 );
formatted = make_stack();
t = make_string();
for( i = 0; i < total; ++i )
{
column = i % cols;
target = column * rows + i / cols;
if ( target < entries->used )
{
s = ( struct string *)entries->values[ target ];
snprintf( line, width, mask, s->str );
ptr = line;
while( *ptr )
string_append( t, *ptr++ );
}
if ( column == cols - 1 )
{
while( t->used < width )
string_append( t, ' ' );
stack_push( formatted, t );
t = make_string();
}
}
string_free( t );
free( line );
return formatted;
}
struct stack *format_possibilities_of_strings( struct stack *entries, struct stack *lengths )
{
int i, l, max = 1, cols, rows, total, column, target, width;
char mask[ 10 ], *line, *ptr;
struct stack *formatted;
char *s;
struct string *t;
for( i = 0; i < lengths->used; ++i )
{
l = ( int )lengths->values[ i ];
if ( l > max )
max = l;
}
++max;
do_cols( "format_possibilities", NULL );
width = number( ( *( struct object **)stack->top )->data.atom );
stack_pop( stack );
line = memory( width + 1 );
cols = --width / max;
if ( cols == 0 )
cols = 1;
rows = ( entries->used + cols ) / cols;
total = rows * cols;
snprintf( mask, sizeof( mask ), "%%-%ds ", max - 1 );
formatted = make_stack();
t = make_string();
for( i = 0; i < total; ++i )
{
column = i % cols;
target = column * rows + i / cols;
if ( target < entries->used )
{
s = ( char *)entries->values[ target ];
snprintf( line, width, mask, s );
for( ptr = line; *ptr; ++ptr )
string_append( t, *ptr );
}
if ( column == cols - 1 )
{
while( t->used < width )
string_append( t, ' ' );
stack_push( formatted, t );
t = make_string();
}
}
string_free( t );
free( line );
return formatted;
}
struct string *find_common_prefix( struct stack *entries )
{
struct stack *e2 = NULL;
struct string *s, *t, *p;
if ( entries->used == 0 )
return NULL;
p = make_string();
if ( entries->used == 1 )
{
s = ( struct string *)entries->values[ 0 ];
string_assign( p, s->str, s->used );
return p;
}
{
int i, j, k, min = 10000;
for( i = 0; i < 2; ++i )
{
for( j = 0; j < entries->used; ++j )
{
s = ( struct string *)entries->values[ j ];
if ( s->used < min )
min = s->used;
}
s = ( struct string *)entries->values[ 0 ];
for( j = 0; j < min; ++j )
{
for( k = 1; k < entries->used; ++k )
{
t = ( struct string *)entries->values[ k ];
if ( s->str[ j ] != t->str[ j ] )
goto NEXT;
}
string_append( p, s->str[ j ] );
}
NEXT:
if ( p->used || i == 1 )
break;
e2 = make_stack();
for( j = 0; j < entries->used; ++j )
{
s = ( struct string *)entries->values[ j ];
if ( strcmp( s->str, "../" ) && strcmp( s->str, "./" ))
stack_push( e2, s );
}
if ( e2->used == 1 )
{
s = ( struct string *)e2->values[ 0 ];
string_assign( p, s->str, s->used );
break;
}
min = 10000;
entries = e2;
}
}
if ( e2 != NULL )
stack_free( e2 );
return p;
}
struct string *find_common_prefix_of_strings( struct stack *entries, struct stack *lengths )
{
char *s, *t;
struct string *p;
int l;
if ( entries->used == 0 )
return NULL;
p = make_string();
if ( entries->used == 1 )
{
string_assign( p, ( char *)entries->values[ 0 ], ( int )lengths->values[ 0 ] );
return p;
}
{
int j, k, min = MAXNAMLEN;
for( j = 0; j < entries->used; ++j )
{
l = ( int )lengths->values[ j ];
if ( l < min )
min = l;
}
s = ( char *)entries->values[ 0 ];
for( j = 0; j < min; ++j )
{
for( k = 1; k < entries->used; ++k )
{
t = ( char *)entries->values[ k ];
if ( s[ j ] != t[ j ] )
goto NEXT;
}
string_append( p, s[ j ] );
}
}
NEXT:
return p;
}
struct string *merge( char *first, char *second )
{
regmatch_t matches[ 1 ];
int result, length;
struct string *merged;
char *ptr;
result = regexec( &merge_regex, first, 1, matches, 0 );
if ( result && result != REG_NOMATCH )
{
char err[ 80 ];
regerror( result, &merge_regex, err, sizeof( err ));
fprintf( stderr, "merge: regexec(): %s\n.", err );
return NULL;
}
merged = make_string( );
if ( result != REG_NOMATCH )
{
int i;
length = strlen( first ) - ( matches[ 0 ].rm_eo - matches[ 0 ].rm_so );
for( i = 0; i < length; ++i )
string_append( merged, first[ i ] );
}
else
string_assign( merged, first, strlen( first ));
ptr = second;
while( *ptr )
string_append( merged, *ptr++ );
return merged;
}
void *complete( char *name, int display, int fd, int recurse )
{
struct stack *p, *f;
struct string *s, *completion = NULL;
int i;
char *source;
totally_complete = 0;
p = f = NULL;
source = expand_tilde( name );
AGAIN:
p = find_possibilities( source );
if ( p == NULL )
{
if ( display )
return str_dup( "", 0 );
completion = make_string();
}
else if ( p->used == 1 )
{
s = ( struct string *)p->values[ 0 ];
completion = merge( source, s->str );
if ( *( completion->top - 1) == '/' )
{
stack_free( p );
string_free( s );
free( source );
source = str_dup( completion->str, completion->used );
string_free( completion );
if ( recurse )
goto AGAIN;
else
return source;
}
totally_complete = 1;
}
else if ( p->used )
{
s = find_common_prefix( p );
if ( s->used )
{
completion = merge( source, s->str );
string_free( s );
if ( *( completion->top - 1 ) == '/' )
{
for( i = 0; i < p->used; ++i )
string_free( ( struct string *)p->values[ i ] );
stack_free( p );
free( source );
source = str_dup( completion->str, completion->used );
string_free( completion );
if ( recurse )
goto AGAIN;
else
return source;
}
}
else
{
completion = make_string();
string_assign( completion, source, strlen( source ));
if ( completion->used && *( completion->top - 1 ) != '/' )
string_append( completion, '/' );
}
f = format_possibilities( p );
if ( display )
{
if ( f->used )
fwrite( "\r\n", 2, 1, stdout );
while( f->used )
{
s = ( struct string *)stack_pop( f );
fwrite( s->str, s->used, 1, stdout );
fwrite( "\r\n", 2, 1, stdout );
string_free( s );
}
stack_free( f );
}
}
if ( p != NULL && p->used )
for( i = 0; i < p->used; ++i )
{
s = ( struct string *)p->values[ i ];
string_free( s );
}
if ( p != NULL )
stack_free( p );
if ( completion == NULL )
{
completion = make_string();
string_assign( completion, source, strlen( source ));
}
free( source );
if ( !display )
{
if ( f == NULL )
f = make_stack();
stack_push( f, completion );
return f;
}
name = str_dup( completion->str, completion->used );
string_free( completion );
return name;
}
int check_args( char *syntax, struct object *args )
{
struct object *ptr, *item;
int total, idx, count, type, result, limit, t, l;
total = ( int)stack_pop( arg_stack );
if ( total == 0 )
{
if ( args == NULL )
return 0;
print_err( ERR_ARGS, syntax, 0, -1 );
return 1;
}
else if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
stack_truncate( arg_stack, total );
return 1;
}
idx = arg_stack->used - total;
limit = arg_stack->used;
ptr = args;
count = 0;
while( ptr != NULL )
{
++count;
if ( idx == limit )
break;
type = ( int)arg_stack->values[ idx++ ];
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, count, -1 );
stack_truncate( arg_stack, total );
return 1;
}
item = *( struct object **)stack->top;
l = islist( item->flags );
if ( numberp( item->flags ) )
t = ATOM_FIXNUM;
else
t = ( l ? -1 : type( item->data.atom->flags ));
switch( type )
{
case ERR_SYMBOL:
if ( l || t != ATOM_SYMBOL )
{
print_err( ERR_ARG_TYPE, syntax, count, ERR_SYMBOL );
stack_truncate( arg_stack, total );
return 1;
}
break;
case ERR_STRING:
if ( l || t != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, count, ERR_STRING );
stack_truncate( arg_stack, total );
return 1;
}
break;
case ERR_FIXNUM:
if ( l || numberp( item->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, count, ERR_FIXNUM );
stack_truncate( arg_stack, total );
return 1;
}
break;
case ERR_REGEXP:
if ( l || t != ATOM_REGEXP )
{
print_err( ERR_ARG_TYPE, syntax, count, ERR_REGEXP );
stack_truncate( arg_stack, total );
return 1;
}
break;
case ERR_TABLE:
if ( l || t != ATOM_TABLE )
{
print_err( ERR_ARG_TYPE, syntax, count, ERR_TABLE );
stack_truncate( arg_stack, total );
return 1;
}
break;
case ERR_STACK:
if ( l || t != ATOM_STACK )
{
print_err( ERR_ARG_TYPE, syntax, count, ERR_STACK );
stack_truncate( arg_stack, total );
return 1;
}
break;
case ERR_ATOM:
if ( l )
{
print_err( ERR_ARG_TYPE, syntax, count, ERR_ATOM );
stack_truncate( arg_stack, total );
return 1;
}
break;
case ERR_LIST:
if ( l == 0 )
{
print_err( ERR_ARG_TYPE, syntax, count, ERR_LIST );
stack_truncate( arg_stack, total );
return 1;
}
break;
case ERR_CLOSURE:
if ( l || ( t != ATOM_CLOSURE && t != ATOM_MACRO ))
{
print_err( ERR_ARG_TYPE, syntax, count, ERR_CLOSURE );
stack_truncate( arg_stack, total );
return 1;
}
break;
case ERR_RECORD:
if ( l || t != ATOM_RECORD )
{
print_err( ERR_ARG_TYPE, syntax, count, ERR_RECORD );
stack_truncate( arg_stack, total );
return 1;
}
break;
}
ptr = ptr->next;
}
if ( ptr != NULL )
{
print_err( ERR_MORE_ARGS, syntax, --count, -1 );
result = 1;
}
else if ( idx < limit )
{
print_err( ERR_MISSING_ARG, syntax, ++count, -1 );
result = 1;
}
else
result = 0;
stack_truncate( arg_stack, total );
return result;
}
struct object *make_atom_from_record( struct object **record )
{
struct object *obj;
struct atom *entry;
char buffer[ 128 ];
snprintf( buffer, sizeof( buffer ), "<RECORD#%d>", record_counter++ );
entry = get_id( buffer, strlen( buffer ), 1 );
if ( entry->flags == 0 )
{
entry->flags = ATOM_RECORD;
entry->data.record = record;
}
obj = make_object();
obj->data.atom = entry;
return obj;
}
struct object *make_atom_from_stack( struct stack *stk )
{
struct object *object;
struct atom *entry;
char buffer[ 64 ];
snprintf( buffer, sizeof( buffer ), "<STACK#%d>", stack_counter++ );
entry = get_id( buffer, strlen( buffer ), 1 );
entry->flags = ATOM_STACK;
entry->data.stack = stk;
object = make_object();
object->data.atom = entry;
return object;
}
struct object *make_atom_from_number( int i )
{
struct object *object;
object = make_object();
setnumber( object->flags );
object->data.atom = toptr( i );
return object;
}
#ifdef SQL
struct object *make_atom_from_db( sqlite3 *db )
{
struct atom *entry;
struct object *obj;
char buffer[ 64 ];
snprintf( buffer, sizeof( buffer ), "<DB#%d>", db_counter++ );
entry = get_id( buffer, strlen( buffer ), 1 );
entry->flags = ATOM_DB;
entry->data.db = db;
obj = make_object();
obj->data.atom = entry;
return obj;
}
int do_sqlitep( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
if ( islist( car->flags ) == 0 &&
numberp( car->flags ) == 0 &&
type( car->data.atom->flags ) == ATOM_DB )
stack_push( stack, make_atom_from_number( 1 ));
else
stack_push( stack, make_atom_from_number( 0 ));
}
return 0;
}
#endif
struct object *make_atom_from_string( char *s, int len )
{
struct atom *entry;
struct object *object;
struct string *new;
new = make_string();
if ( len == -1 )
len = strlen( s );
string_assign( new, s, len );
string_prepend( new, '"' );
entry = get_id( new->str, new->used, 1 );
string_free( new );
if ( entry->flags == 0 )
{
entry->flags = ATOM_STRING;
entry->data.string = memory( sizeof( struct lstring ));
entry->data.string->length = len;
entry->data.string->string = &entry->syntax[ 1 ];
}
object = make_object();
object->data.atom = entry;
return object;
}
struct object *make_atom_from_symbol( char *symbol )
{
struct atom *entry;
struct object *object;
entry = get_id( symbol, strlen( symbol ), 1 );
if ( entry->flags == 0 )
{
entry->flags = ATOM_SYMBOL;
entry->data.record = NULL;
}
object = make_object();
object->data.atom = entry;
return object;
}
struct object *make_atom_from_regexp( regex_t *rx )
{
struct atom *entry;
struct object *object;
char buffer[ 128 ];
snprintf( buffer, sizeof( buffer ), "<REGEX#%d>", rx_counter++ );
entry = get_id( buffer, strlen( buffer ), 1 );
entry->flags = ATOM_REGEXP;
entry->data.regexp = rx;
object = make_object();
object->data.atom = entry;
return object;
}
struct object *duplicate_object( struct object *ptr )
{
struct object *ptr2, *ptr3, *top;
if ( ptr == NULL )
return NULL;
if ( islist( ptr->flags ) == 0 )
{
ptr2 = make_object();
*ptr2 = *ptr;
return ptr2;
}
top = make_object();
setlist( top->flags );
top->data.head = top->next = NULL;
ptr2 = NULL;
ptr = ptr->data.head;
while( ptr != NULL )
{
ptr3 = ptr2;
if ( islist( ptr->flags ) == 0 )
{
ptr2 = make_object();
*ptr2 = *ptr;
}
else
ptr2 = duplicate_object( ptr );
if ( top->data.head == NULL )
top->data.head = ptr2;
else
ptr3->next = ptr2;
ptr = ptr->next;
}
return top;
}
int do_lines( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
{
struct winsize winsize;
if ( ioctl( 1, TIOCGWINSZ, &winsize ) < 0 )
{
fprintf( stderr, "%s: %s.\n", syntax, strerror( errno ));
return 1;
}
stack_push( stack, make_atom_from_number( winsize.ws_row ));
}
return 0;
}
int do_cols( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
{
struct winsize winsize;
if ( ioctl( 1, TIOCGWINSZ, &winsize ) < 0 )
{
fprintf( stderr, "%s: %s.\n", syntax, strerror( errno ));
return 1;
}
stack_push( stack, make_atom_from_number( winsize.ws_col ));
}
return 0;
}
int do_progn( char *syntax, struct object *args )
{
struct object *ptr, *result = NULL;
int i;
if ( args == NULL )
{
fprintf( stderr, "%s: missing body.\n", syntax );
return 1;
}
for( i = 1, ptr = args; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: error evaluating body expression %d.\n",
syntax, i );
return 1;
}
result = stack_pop( stack );
}
stack_push( stack, result );
return 0;
}
int do_cons( char *syntax, struct object *args )
{
struct object *car1, *car2, *new, *new2;
stack_push( arg_stack, ( void *)-1);
stack_push( arg_stack, ( void *)ERR_LIST );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
new2 = duplicate_object( car1 );
new2->next = car2->data.head;
new = make_object();
setlist( new->flags );
new->data.head = new2;
stack_push( stack, new );
return 0;
}
int do_quote( char *syntax, struct object *args )
{
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
stack_push( stack, args );
return 0;
}
int do_car( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)ERR_LIST );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
if ( car->data.head == NULL )
{
fprintf( stderr, "%s: argument is empty list.\n", syntax );
return 1;
}
else
stack_push( stack, car->data.head );
return 0;
}
int do_cdr( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)ERR_LIST );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
if ( car->data.head == NULL )
{
fprintf( stderr, "%s: argument is empty list.\n", syntax );
return 1;
}
else
{
stack_push( stack, make_object() );
setlist( ( *( struct object **)stack->top )->flags );
( *( struct object **)stack->top )->data.head = car->data.head->next;
}
return 0;
}
int do_eq( char *syntax, struct object *args )
{
struct object *car1, *car2;
int i;
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
i = 0;
if ( islist( car1->flags ) == 0 &&
islist( car2->flags ) == 0 )
{
i = ( car1->data.atom == car2->data.atom );
}
else if ( islist( car1->flags ) == 1 &&
islist( car2->flags ) == 1 )
{
i = (( car1->data.head == NULL && car2->data.head == NULL ) || car1 == car2 );
}
stack_push( stack, make_atom_from_number( i ));
return 0;
}
int do_atomp( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
stack_push( stack, ( islist( car->flags ) ? make_atom_from_number( 0 ) :
make_atom_from_number( 1 )));
return 0;
}
int do_append( char *syntax, struct object *args )
{
struct object *car1, *car2, *ptr;
stack_push( arg_stack, ( void *)ERR_LIST );
stack_push( arg_stack, ( void *)ERR_LIST );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
car2 = duplicate_object( car2 );
ptr = car1->data.head;
if ( ptr == NULL )
{
stack_push( stack, car2 );
return 0;
}
car1 = duplicate_object( car1 );
ptr = car1->data.head;
while( ptr->next != NULL )
ptr = ptr->next;
ptr->next = car2->data.head;
stack_push( stack, car1 );
return 0;
}
int do_set( char *syntax, struct object *args )
{
struct object *car1, *car2;
stack_push( arg_stack, ( void *)ERR_SYMBOL );
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( set_local( car1->data.atom->id, car2 ))
insert_binding( car1->data.atom->id, car2 );
stack_push( stack, car2 );
return 0;
}
int do_eval( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
return 1;
}
return 0;
}
int do_if( char *syntax, struct object *args )
{
struct object *result;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 1, -1 );
return 1;
}
if ( args->next == NULL )
{
fprintf( stderr, "%s: missing consquent argument.\n", syntax );
return 1;
}
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: evaluation of test expression failed.\n",
syntax );
return 1;
}
result = stack_pop( stack );
if (( islist( result->flags ) == 1 && result->data.head == NULL ) ||
( islist( result->flags ) == 0 && ( result->data.atom == NULL ||
result->data.atom == empty->data.atom )))
{
if ( args->next->next == NULL )
{
stack_push( stack, result );
return 0;
}
if ( do_progn( syntax, args->next->next ) )
{
if ( !stop )
fprintf( stderr,
"%s: evaluation of alternative expression(s) failed.\n",
syntax );
return 1;
}
return 0;
}
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: evaluation of consequent expression failed.\n",
syntax );
return 1;
}
return 0;
}
int do_and( char *syntax, struct object *args )
{
struct object *ptr, *result = NULL;
int i;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
i = 1;
for( ptr = args; ptr != NULL; ptr = ptr->next )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, i, 0 );
return 1;
}
result = stack_pop( stack );
if (( islist( result->flags ) == 1 && result->data.head == NULL ) ||
( islist( result->flags ) == 0 && ( result->data.atom == NULL ||
result->data.atom == empty->data.atom )))
break;
++i;
}
stack_push( stack, result );
return 0;
}
int do_or( char *syntax, struct object *args )
{
struct object *ptr, *result = NULL;
int i;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
for( i = 1, ptr = args; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, i, -1 );
return 1;
}
result = stack_pop( stack );
if (( islist( result->flags ) == 1 && result->data.head == NULL ) ||
( islist( result->flags ) == 0 && ( result->data.atom == NULL ||
result->data.atom == empty->data.atom )))
continue;
break;
}
stack_push( stack, result );
return 0;
}
int do_list( char *syntax, struct object *args )
{
struct object *ptr, **new, *result;
int i, j;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
for( i = 0, ptr = args; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, i + 1, -1 );
return 1;
}
}
result = make_object();
setlist( result->flags );
new = &result->data.head;
for( j = i; j; --j )
{
*new = duplicate_object( ( struct object *)stack->values[ stack->used - j ] );
( *new )->next = NULL;
new = &( *new )->next;
}
stack_truncate( stack, i );
stack_push( stack, result );
return 0;
}
int do_not( char *syntax, struct object *args )
{
struct object *result;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
if ( args->next )
{
print_err( ERR_MORE_ARGS, syntax, 1, -1 );
return 1;
}
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
return 1;
}
result = stack_pop( stack );
if (( islist( result->flags ) == 1 && result->data.head == NULL ) ||
( islist( result->flags ) == 0 && ( result->data.atom == NULL ||
result->data.atom == empty->data.atom )))
stack_push( stack, make_atom_from_number( 1 ));
else
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
void do_print_objects_strings_unquoted( struct object *ptr, int recursive, int descr )
{
while( ptr != NULL )
{
if ( islist( ptr->flags ) == 1 )
{
fputc( '(', ( descr ? stderr : stdout ));
do_print_objects_strings_unquoted( ptr->data.head, 1, descr );
fputc( ')', ( descr ? stderr : stdout ));
}
else
{
if ( numberp( ptr->flags ) )
fprintf( ( descr ? stderr : stdout ), "%i", number( ptr->data.atom ));
else
{
char *str;
int len;
if ( recursive == 0 && type( ptr->data.atom->flags ) == ATOM_STRING )
{
str = ptr->data.atom->data.string->string;
len = ptr->data.atom->data.string->length;
}
else
{
str = ptr->data.atom->syntax;
len = ptr->data.atom->len;
}
fwrite( str, len, 1, ( descr ? stderr : stdout ));
if ( recursive && type( ptr->data.atom->flags ) == ATOM_STRING )
fputc( '"', ( descr ? stderr : stdout ));
}
}
if ( recursive == 0 )
break;
if (( ptr = ptr->next ) != NULL )
fputc( ' ', ( descr ? stderr : stdout ));
}
}
int do_print( char *syntax, struct object *args )
{
struct object *ptr;
int i;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
for( i = 1, ptr = args; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, i, -1 );
return 1;
}
do_print_objects_strings_unquoted( stack_pop( stack ), 0, 0 );
}
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_println( char *syntax, struct object *args )
{
struct object *ptr;
int i;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
for( i = 1, ptr = args; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, i, -1 );
return 1;
}
do_print_objects_strings_unquoted( stack_pop( stack ), 0, 0 );
}
fputc( '\n', stdout );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_newline( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
fputc( '\n', stdout );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_load( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
return load( car->data.atom->data.string->string );
}
void nocanon( char *syntax )
{
if ( mode == 0 )
return;
if ( isatty( 0 ) == 0 )
return;
if ( isatty( 0 ) )
{
struct termios termios;
cfmakeraw( &termios );
termios.c_cc[ VMIN ] = 1;
termios.c_cc[ VTIME ] = 0;
AGAIN:
if ( tcsetattr( 0, TCSANOW, &termios ) < 0 )
{
if ( errno == EAGAIN || errno == EINTR )
goto AGAIN;
fprintf( stderr, "%s: tcsetattr: %s.\n", syntax, strerror( errno ));
return;
}
mode = 0;
}
return;
}
void blocking_fd( int fd )
{
int flags;
/*
* I stole this from /usr/src/bin/sh/input.c
*
* When running msh.munger example program as my shell, I would launch X,
* then exit, and descriptor 0 would be in non-blocking mode, causing
* read() to fail with errno set to EAGAIN. So I made "canon" check for
* this and correct. /bin/sh does the same thing.
*/
flags = fcntl( fd, F_GETFL, 0 );
if ( flags >= 0 && ( flags & O_NONBLOCK ))
{
flags &= ~O_NONBLOCK;
fcntl( fd, F_SETFL, flags );
}
}
void canon( char *syntax )
{
if ( mode )
return;
if ( isatty( 0 ) < 0 )
return;
AGAIN:
if ( tcsetattr( 0, TCSANOW, &canon_termios ) < 0 )
{
if ( errno == EAGAIN || errno == EINTR )
goto AGAIN;
fprintf( stderr, "%s: tcsetattr: %s.\n", syntax, strerror( errno ));
return;
}
blocking_fd( 0 );
mode = 1;
return;
}
int do_complete( char *syntax, struct object *args )
{
struct object *car, **ptr, *result;
struct stack *results;
struct string *str;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
results = ( struct stack *)complete( car->data.atom->data.string->string, 0, 1, 1 );
result = make_object();
setlist( result->flags );
ptr = &result->data.head;
while( results->used )
{
str = ( struct string *)stack_pop( results );
*ptr = make_atom_from_string( str->str, str->used );
string_free( str );
ptr = &( *ptr )->next;
}
stack_free( results );
stack_push( stack, result );
return 0;
}
int getline_from_file( char *syntax, int reset )
{
static char buffer[ 102400 ] = "", *ptr = buffer;
int result;
static int len = 0;
struct string *s;
switch( reset )
{
case 1:
stack_push( input_buffer_stack, str_dup( ptr, len ));
stack_push( input_buffer_stack, ( void *)len );
buffer[ 0 ] = '\0';
len = 0;
ptr = buffer;
return 0;
case 2:
if ( input_buffer_stack->used )
{
len = ( int )stack_pop( input_buffer_stack );
ptr = ( char * )stack_pop( input_buffer_stack );
bcopy( ptr, buffer, len );
free( ptr );
ptr = buffer;
}
else
{
buffer[ 0 ] = '\0';
ptr = buffer;
len = 0;
}
return 0;
}
s = make_string();
string_append( s, '"' );
for( ; ; )
{
if ( len == 0 )
{
if (( result = read( 0, buffer, sizeof( buffer ) - 1 )) < 0 )
{
if ( errno == EINTR )
continue;
fprintf( stderr, "%s: read: %s.\n", syntax, strerror( errno ));
string_free( s );
return 1;
}
else if ( result == 0 )
{
len = 0;
if ( s->used > 1 )
{
stack_push( stack, make_atom_directly_from_string( s->str, s->used ));
free( s );
}
else
{
stack_push( stack, make_atom_from_number( 0 ));
string_free( s );
}
return 0;
}
buffer[ result ] = '\0';
ptr = buffer;
len = result;
}
while( len )
{
string_append( s, *ptr );
--len;
if ( *ptr++ == 10 )
goto NEXT;
}
}
NEXT:
stack_push( stack, make_atom_directly_from_string( s->str, s->used ));
free( s );
return 0;
}
int do_rescan_path( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
free_executables();
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
void make_executables()
{
DIR *dir;
struct dirent *dp;
int i, j;
char *ptr, *ptr2;
struct stack *stk;
if ( path == NULL && (( path = getenv( "PATH" )) == NULL ))
return;
stk = make_stack();
ptr2 = path = str_dup( path, strlen( path ));
while(( ptr = strsep( &ptr2, ":" )) != NULL )
if ( *ptr != '\0')
stack_push( stk, ptr );
if ( stk->used == 0 )
{
free( path );
path = NULL;
stack_free( stk );
return;
}
executables = make_stack();
for( i = 0; i < stk->used; ++i )
{
if (( dir = opendir( ( char *)stk->values[ i ] )) == NULL )
{
if ( errno == ENOENT )
continue;
fprintf( stderr, "make_executables(): opendir: %s.\n", strerror( errno ));
free( path );
path = NULL;
stack_free( stk );
return;
}
readdir( dir );
readdir( dir );
while(( dp = readdir( dir )) != NULL )
{
stack_push( executables, str_dup( dp->d_name, dp->d_namlen ));
stack_push( executables, ( void *)(( int )dp->d_namlen ));
stack_push( executables, ( char *)stk->values[ i ] );
}
closedir( dir );
}
while( stk->used )
stack_pop( stk );
while( executables->used )
{
ptr2 = ( char *)stack_pop( executables );
j = ( int )stack_pop( executables );
ptr = ( char *)stack_pop( executables );
for( i = 0; i < stk->used; i += 3 )
if ( !strcmp( stk->values[ i ], ptr ))
{
free( ptr );
ptr = NULL;
break;
}
if ( ptr != NULL )
{
stack_push( stk, ptr );
stack_push( stk, ( void *)j );
stack_push( stk, ptr2 );
}
}
stack_free( executables );
executables = stk;
/*
* path gets freed in free_executables().
*/
}
int do_command_lookup( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
char *str, *ptr;
struct string *s;
int i;
car = stack_pop( stack );
str = car->data.atom->data.string->string;
if ( executables == NULL )
make_executables();
for( i = 0; i < executables->used; i += 3 )
if ( strcmp( str, ( char *)executables->values[ i ] ) == 0 )
break;
if ( i == executables->used )
stack_push( stack, empty );
else
{
s = make_string();
string_append( s, '"' );
for( ptr = ( char *)executables->values[ i + 2 ]; *ptr; ++ptr )
string_append( s, *ptr );
if ( *s->top != '/' )
string_append( s, '/' );
for( ptr = str; *ptr; ++ptr )
string_append( s, *ptr );
stack_push( stack, make_atom_directly_from_string( s->str, s->used ));
free( s );
}
}
return 0;
}
struct string *complete_from_path( char *syntax, char *input, int len, int fd )
{
int i, j;
char *ptr;
struct stack *stk, *stk2, *f;
struct string *s, *result;
stk = make_stack();
stk2 = make_stack();
if ( executables == NULL )
make_executables();
for( i = 0; i < executables->used; i += 3 )
{
ptr = ( char *)executables->values[ i ];
if ( !len )
{
stack_push( stk, ptr );
stack_push( stk2, executables->values[ i + 1 ] );
}
else
{
if (( j = ( int )executables->values[ i + 1 ] ) < len )
continue;
if ( strncmp( ptr, input, len ) == 0 )
{
stack_push( stk, ptr );
stack_push( stk2, ( void *)j );
}
}
}
f = NULL;
switch( stk->used )
{
case 0:
result = make_string();
string_assign( result, input, len );
break;
case 1:
result = make_string();
string_assign( result, ( char *)stk->values[ 0 ], ( int )stk2->values[ 0 ] );
string_append( result, ' ' );
break;
default:
result = find_common_prefix_of_strings( stk, stk2 );
f = format_possibilities_of_strings( stk, stk2 );
if ( f->used )
{
fwrite( "\r\n", 2, 1, stdout );
while( f->used )
{
s = ( struct string *)stack_pop( f );
fwrite( s->str, s->used, 1, stdout );
fwrite( "\r\n", 2, 1, stdout );
string_free( s );
}
}
stack_free( f );
}
stack_free( stk2 );
stack_free( stk );
return result;
}
void add_history( struct string *s )
{
int i;
string_chop( s );
if ( s->used == 0 )
return;
for( i = 0; i < history->used; ++i )
if ( strcmp( ( char *)history->values[ i ], s->str ) == 0 )
break;
if ( i == history->used - 1 )
return;
if ( history->used && i < history->used )
{
char *tmp;
tmp = history->values[ i ];
for( ; i < history->used - 1; ++i )
history->values[ i ] = history->values[ i + 1 ];
history->values[ i ] = tmp;
return;
}
if ( history->used == 500 )
{
for( i = 0; i < history->used - 1; ++i )
history->values[ i ] = history->values[ i + 1 ];
history->values[ i ] = str_dup( s->str, s->used );
}
else
stack_push( history, str_dup( s->str, s->used ));
}
char *back_history()
{
if ( history->used == 0 || history_ptr == 0 )
return NULL;
return ( char *)history->values[ --history_ptr ];
}
char *forw_history()
{
if ( history->used == 0 || history_ptr == history->used )
return NULL;
++history_ptr;
if ( history_ptr == history->used )
return NULL;
else
return ( char*)history->values[ history_ptr ];
}
char *search_history( char *str, int dir )
{
char *ptr;
int old_history_ptr;
char *( *func )();
old_history_ptr = history_ptr;
func = ( dir ? forw_history : back_history );
for( ptr = func(); ptr != NULL; ptr = func() )
if ( strstr( ptr, str ) != NULL )
break;
if ( ptr == NULL )
history_ptr = old_history_ptr;
return ptr;
}
#define forw_search_history( s ) search_history( s, 1 )
#define back_search_history( s ) search_history( s, 0 )
void display_line( struct string *s, struct string *after,
char *prompt, int plen, int tabstop,
struct stack *offsets )
{
int len, idx, space;
static struct string *working = NULL;
char *ptr;
if ( s == NULL )
{
if ( working != NULL )
string_free( working );
working = NULL;
return;
}
if ( working == NULL )
working = make_string();
else
string_truncate( working );
idx = 0;
for( ptr = s->str; *ptr; ++ptr )
if ( *ptr != '\t' )
string_append( working, *ptr );
else
{
len = ( int )offsets->values[ idx++ ];
while( len-- )
string_append( working, ' ' );
}
if ( LINES <= 0 || COLS <= 0 )
return;
putp( tgoto( cm, 0, LINES - 1 ));
putp( ce );
len = working->used;
idx = 0;
space = ( COLS - 1 ) - plen;
if ( space > 0 )
while( len >= space )
{
len -= space;
idx += space;
space = ( COLS - 1 );
}
if ( idx == 0 && plen )
fwrite( prompt, plen, 1, stdout );
if ( len )
fwrite( working->str + idx, len, 1, stdout );
if ( ! idx )
len += plen;
idx = after->used;
space = ( COLS - 1 ) - len;
if ( space > 0 )
while( --idx >= 0 && space-- )
fputc( after->str[ idx ], stdout );
putp( tgoto( cm, len, LINES - 1 ));
fflush( stdout );
}
int do_getline( char *syntax, struct object *args )
{
struct object *car1 = NULL, *car2 = NULL;
if ( args != NULL )
{
if ( args->next != NULL && args->next->next != NULL )
{
print_err( ERR_MORE_ARGS, syntax, 2, -1 );
return 1;
}
stack_push( stack, args );
if ( evaluate())
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
return 1;
}
car1 = stack_pop( stack );
if ( islist( car1->flags ) == 1 ||
numberp( car1->flags ) ||
type( car1->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_STRING );
return 1;
}
if ( args->next != NULL )
{
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, -1 );
return 1;
}
car2 = stack_pop( stack );
if ( islist( car2->flags ) == 1 || numberp( car2->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 2, ERR_FIXNUM);
return 1;
}
}
}
if ( ! isatty( 0 ) )
return getline_from_file( syntax, 0 );
{
struct string *s, *after, *clip, *search;
struct stack *offsets;
unsigned char c;
char *name, *original_s, *original_after, *old;
int tabstop, result, eof, was_canon, name_len,
original_len, after_len, offset;
/*
* Update LINES and COLS in case a sigwinch was caught by a child
* process, and not us, leaving them inaccurate.
*/
sigwinch_handler( 0 );
sigwinch = 0;
if ( LINES <= 0 || COLS <= 0 )
{
fprintf( stderr, "%s: cannot determine size of screen!", syntax );
return 1;
}
if ( ( int)ce <= 0 || ( int)cm <= 0 )
return getline_from_file( syntax, 0 );
original_s = original_after = NULL;
original_len = after_len = 0;
putp( tgoto( cm, 0, LINES - 1 ));
putp( ce );
fflush( stdout );
if ( car2 == NULL )
tabstop = 8;
else
tabstop = number( car2->data.atom );
if ( tabstop < -3 )
{
fprintf( stderr, "%s: argument two out of range: %d.\n", syntax, tabstop );
return 1;
}
eof = 0;
was_canon = mode;
nocanon( syntax );
if ( car1 != NULL )
{
name = car1->data.atom->data.string->string;
name_len = car1->data.atom->data.string->length;
}
else
{
name = "";
name_len = 0;
}
s = make_string();
after = make_string();
clip = make_string();
search = make_string();
offsets = make_stack();
offset = 0;
old = NULL;
for( ; ; )
{
display_line( s, after, name, name_len, tabstop, offsets );
result = read( 0, &c, 1 );
if ( result < 0 )
{
if ( errno == EINTR || errno == EAGAIN )
continue;
if ( was_canon )
canon( syntax );
string_free( s );
string_free( after );
string_free( clip );
string_free( search );
stack_free( offsets );
fprintf( stderr, "%s: read: %s.\n", syntax, strerror( errno ));
return 1;
}
else if ( result == 0 )
{
eof = 1;
break;
}
switch( c )
{
/* C-k */
case 11:
if ( tabstop <= 0 )
{
char *ptr;
string_truncate( clip );
for( ptr = after->str; *ptr; ++ptr )
string_prepend( clip, *ptr );
string_truncate( after );
}
break;
/* C-y */
case 25:
if ( tabstop <= 0 && clip->used )
{
char *ptr;
for( ptr = clip->str; *ptr ; ++ptr )
string_append( s, *ptr );
}
break;
/* C-b */
case '\002':
if ( tabstop <= 0 && s->used )
{
string_append( after, *( s->top - 1 ));
string_chop( s );
}
break;
/* M-b */
case 226:
if ( tabstop <= 0 )
{
while( s->used && !isalnum( s->str[ s->used - 1 ] ))
{
string_append( after, *( s->top - 1 ));
string_chop( s );
}
while( s->used && isalnum( s->str[ s->used - 1 ] ))
{
string_append( after, *( s->top - 1 ));
string_chop( s );
}
}
break;
/* C-f */
case '\006':
if ( tabstop <= 0 && after->used )
{
string_append( s, *( after->top - 1 ));
string_chop( after );
}
break;
/* M-f */
case 230:
if ( tabstop <= 0 )
{
while( after->used && !isalnum( after->str[ after->used - 1 ] ))
{
string_append( s, *( after->top - 1 ));
string_chop( after );
}
while( after->used && isalnum( after->str[ after->used - 1 ] ))
{
string_append( s, *( after->top - 1 ));
string_chop( after );
}
while( after->used && !isalnum( after->str[ after->used - 1 ] ))
{
string_append( s, *( after->top - 1 ));
string_chop( after );
}
}
break;
/* C-a */
case '\001':
if ( tabstop <= 0 )
{
int i;
for( i = s->used; i; --i )
{
string_append( after, *( s->top - 1 ));
string_chop( s );
}
}
break;
/* C-e */
case '\005':
if ( tabstop <= 0 )
{
while( after->used )
{
string_append( s, *( after->top - 1 ));
string_chop( after );
}
}
break;
/* C-h */
case '\010':
if ( s->used )
{
if ( s->str[ s->used - 1 ] == '\t' )
{
result = ( int)stack_pop( offsets );
offset -= result - 1;
}
if ( tabstop <= 0 )
string_assign( clip, s->top - 1, 1 );
string_chop( s );
}
break;
/* C-d */
case '\004':
if ( s->used == 0 && after->used == 0 )
{
eof = 1;
goto BREAK;
}
if ( tabstop <= 0 && after->used )
{
string_assign( clip, after->top - 1, 1 );
string_chop( after );
}
break;
/* C-u */
case '\025':
if ( tabstop <= 0 )
string_assign( clip, s->str, s->used );
stack_truncate( offsets, offsets->used );
string_truncate( s );
offset = 0;
break;
/* C-x */
case 24:
if ( tabstop <= 0 )
{
history_ptr = history->used;
if ( original_s != NULL )
{
string_assign( s, original_s, original_len );
string_assign( after, original_after, after_len );
string_truncate( search );
free( original_s );
free( original_after );
original_s = original_after = NULL;
}
}
break;
/* C-n */
case '\016':
/* C-s */
case '\023':
if ( tabstop <= 0 )
{
char *str;
str = NULL;
if ( c == '\016' )
{
str = forw_history();
if ( str != NULL )
{
string_assign( s, str, strlen( str ));
string_truncate( after );
}
else if ( original_s != NULL )
{
string_assign( s, original_s, original_len );
string_assign( after, original_after, after_len );
string_truncate( search );
free( original_s );
free( original_after );
original_s = original_after = NULL;
}
}
else
{
if ( ! search->used || old == NULL || strcmp( old, s->str ))
string_assign( search, s->str, s->used );
str = forw_search_history( search->str );
if ( str != NULL )
{
old = str;
if ( original_s == NULL )
{
original_s = str_dup( s->str, s->used );
original_after = str_dup( after->str, after->used );
}
string_assign( s, str, strlen( str ));
string_truncate( after );
}
}
}
break;
/* C-p */
case '\020':
/* C-r */
case '\022':
if ( tabstop <= 0 )
{
char *str;
str = NULL;
if ( c == '\020' )
str = back_history();
else
{
if ( ! search->used || old == NULL || strcmp( old, s->str ))
string_assign( search, s->str, s->used );
str = back_search_history( search->str );
if ( str != NULL )
old = str;
}
if ( str != NULL )
{
if ( original_s == NULL )
{
original_s = str_dup( s->str, s->used );
original_len = s->used;
original_after = str_dup( after->str, after->used );
after_len = after->used;
}
string_assign( s, str, strlen( str ));
string_truncate( after );
}
}
break;
/* M-d */
case 228:
if ( tabstop <= 0 )
{
string_truncate( clip );
if ( after->used && !isalnum( after->str[ after->used - 1 ] ))
{
do
{
string_append( clip, *( after->top - 1 ));
string_chop( after );
}
while( after->used && !isalnum( after->str[ after->used - 1 ] ));
}
else
while( after->used && isalnum( after->str[ after->used - 1 ] ))
{
string_append( clip, *( after->top - 1 ));
string_chop( after );
}
}
break;
/* C-w */
case '\027':
if ( tabstop <= 0 )
string_truncate( clip );
if ( s->used && !isalnum( s->str[ s->used - 1 ] ))
{
while( s->used && !isalnum( s->str[ s->used - 1 ] ))
{
if ( s->str[ s->used - 1 ] == '\t' )
{
result = ( int )stack_pop( offsets );
offset -= result - 1;
}
if ( tabstop <= 0 )
string_prepend( clip, *( s->top - 1 ));
string_chop( s );
}
}
else
while( s->used && isalnum( s->str[ s->used - 1 ] ))
{
if ( tabstop <= 0 )
string_prepend( clip, *( s->top - 1 ));
string_chop( s );
}
break;
/* tab */
case '\011':
if ( tabstop > 0 )
{
result = tabstop - ( s->used + offset ) % tabstop;
offset += result - 1;
stack_push( offsets, ( void *)result );
string_append( s, c );
}
else
{
char *ptr, *ptr2;
int length, flag;
flag = 0;
if ( s->used )
{
ptr = &s->str[ s->used - 1 ];
while( ptr > s->str && !isspace( *ptr ))
--ptr;
if ( *ptr == ' ' || *ptr == '/' || *ptr == '.' )
++flag;
while( isspace( *ptr ))
++ptr;
}
else
ptr = "";
if (( tabstop == -1 || tabstop == -3 ) && ! flag )
{
struct string *p;
p = complete_from_path( syntax, s->str, s->used, 0 );
if ( p != NULL )
{
string_assign( s, p->str, p->used );
free( p );
}
}
else
{
length = strlen( ptr );
ptr2 = ( char *)complete( ptr, 1, 0,
(( tabstop == -2 || tabstop == - 3 ) ? 0 : 1 ));
length = s->used - length;
while( s->used > length )
string_chop( s );
for( ptr = ptr2; *ptr; ++ptr )
string_append( s, *ptr );
if ( totally_complete )
string_append( s, ' ' );
free( ptr2 );
}
}
break;
case '\r':
case '\n':
string_prepend( after, '\n' );
fwrite( "\r\n", 2, 1, stdout );
goto BREAK;
default:
if ( c > 31 )
string_append( s, c );
break;
} /* end of switch */
} /* end of for loop */
BREAK:
if ( was_canon )
canon( syntax );
stack_free( offsets );
string_free( clip );
string_free( search );
if ( original_s != NULL )
free( original_s );
if ( original_after != NULL )
free( original_after );
while( after->used )
{
string_append( s, *( after->top - 1 ));
string_chop( after );
}
string_free( after );
if ( !s->used && eof )
stack_push( stack, make_atom_from_number( 0 ));
else
{
stack_push( stack, make_atom_from_string( s->str, s->used ));
if ( tabstop <= 0 )
{
add_history( s );
history_ptr = history->used;
}
}
string_free( s );
}
return 0;
}
int do_fixnump( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
if ( islist( car->flags ))
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
stack_push( stack, make_atom_from_number( ( numberp( car->flags ) )));
return 0;
}
int do_stringp( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
if ( islist( car->flags ) || numberp( car->flags ))
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
if ( type( car->data.atom->flags ) == ATOM_STRING )
stack_push( stack, make_atom_from_number( 1 ));
else
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
int do_split( char *syntax, struct object *args )
{
struct object *car1, *car2, *car3;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
car1 = args;
car2 = args->next;
if ( car2 == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 2, -1 );
return 1;
}
car3 = car2->next;
if ( car3 != NULL )
{
if ( car3->next )
{
print_err( ERR_MORE_ARGS, syntax, 3, -1 );
return 1;
}
}
stack_push( stack, car1 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
return 1;
}
stack_push( stack, car2 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, -1 );
return 1;
}
if ( car3 != NULL )
{
stack_push( stack, car3 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 3, -1 );
return 1;
}
car3 = stack_pop( stack );
if ( numberp( car3->flags ) == 0 || islist( car3->flags ) == 1 )
{
print_err( ERR_ARG_TYPE, syntax, 3, ERR_FIXNUM);
return 1;
}
if ( number( car3->data.atom ) <= 0 )
{
fprintf( stderr, "%s: argument 3 <= 0.\n", syntax );
return 1;
}
}
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( numberp( car1->flags ) ||
islist( car1->flags ) == 1 ||
type( car1->data.atom->flags )!= ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_STRING );
return 1;
}
if ( numberp( car2->flags ) ||
islist( car2->flags ) == 1 ||
type( car2->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, 2, ERR_STRING );
return 1;
}
{
struct object *result;
char *tmp1, *tmp2, *tmp3, *tmp4 = NULL, **results;
int i, len, length, arg3, duped = 0;
results = NULL;
if ( car2->data.atom->data.string->length == 0 )
{
result = make_object();
setlist( result->flags );
result->data.head = car2;
stack_push( stack, result );
return 0;
}
tmp1 = car1->data.atom->data.string->string;
tmp2 = car2->data.atom->data.string->string;
length = car2->data.atom->data.string->length;
len = length;
arg3 = -1;
if ( car3 != NULL )
{
if ( number( car3->data.atom ) <= length )
arg3 = ( number( car3->data.atom )) - 1;
}
if ( arg3 == 0 )
{
result = make_object();
setlist( result->flags );
result->data.head =
make_atom_from_string( car2->data.atom->data.string->string,
car2->data.atom->data.string->length );
stack_push( stack, result );
return 0;
}
else if ( *tmp1 == '\0' )
{
results = ( char **)memory( sizeof( char * ) * ( length + 1 ));
for( i = 0; i <= length; ++i )
results[ i ] = NULL;
if ( arg3 > 0 && arg3 < length )
length = arg3;
for( i = 0; i < length; ++i )
{
results[ i ] = ( char *)memory( 2 );
results[ i ][ 0 ] = tmp2[ i ];
results[ i ][ 1 ] = '\0';
}
if ( arg3 > 0 && arg3 == length )
results[ i ] = str_dup( &tmp2[ i ], len - i );
}
else
{
char *start;
results = ( char **)memory( sizeof( char * ) * ( length + 1 ));
for( i = 0; i <= length; ++i )
results[ i ] = NULL;
i = 0;
tmp4 = tmp3 = str_dup( tmp2, strlen( tmp2 ));
duped = 1;
if ( arg3 > 0 && arg3 < length )
length = arg3;
while( i < length && ( start = strsep( &tmp3, tmp1 )) != NULL )
results[ i++ ] = start;
if ( arg3 > 0 && arg3 == length && tmp3 != NULL )
results[ i ] = tmp3;
}
result = make_object();
setlist( result->flags );
stack_push( stack, result );
if ( *results == NULL )
result->data.head = car2;
else
{
char **ptr;
struct object **ptr2;
ptr2 = &result->data.head;
for( ptr = results; *ptr != NULL; ++ptr )
{
*ptr2 = make_atom_from_string( *ptr, strlen( *ptr ));
ptr2 = &( *ptr2 )->next;
if ( duped == 0 )
free( *ptr );
}
}
free( results );
if ( duped )
free( tmp4 );
}
return 0;
}
int get_join_args( struct object *args, int i, char *syntax )
{
struct object *ptr;
for( ptr = args; ptr != NULL; ptr = ptr->next, ++i )
{
if ( islist( ptr->flags ))
{
if ( ptr->data.head == NULL )
{
print_err( ERR_ARG_TYPE, syntax, i + 1, ERR_STRING );
return 0;
}
if (( i = get_join_args( ptr->data.head, i, syntax )) == 0 )
return 0;
--i;
}
else
{
if ( numberp( ptr->flags ) || type( ptr->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, i + 1, ERR_STRING );
return 0;
}
stack_push( stack, ptr );
}
}
return i;
}
int process_join_args( struct object *args, int i, char *syntax )
{
struct object *ptr, *result;
for( ptr = args; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, i + 1, -1 );
return 0;
}
result = *( struct object **)stack->top;
if ( numberp( result->flags ))
{
print_err( ERR_ARG_TYPE, syntax, i + 1, ERR_STRING );
return 0;
}
else if ( islist( result->flags ))
{
int j;
if ( result->data.head == NULL )
{
print_err( ERR_ARG_TYPE, syntax, i + 1, ERR_STRING );
return 0;
}
j = stack->used;
if (( i = get_join_args( result->data.head, i, syntax )) == 0 )
return 0;
--i;
for( ; j < stack->used; ++j )
stack->values[ j - 1 ] = stack->values[ j ];
stack_pop( stack );
}
else if ( type( result->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, i + 1, ERR_STRING );
return 0;
}
}
return i;
}
int do_join( char *syntax, struct object *args )
{
struct object *car1, *car2;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
car1 = args;
car2 = car1->next;
if ( car2 == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 2, -1 );
return 1;
}
stack_push( stack, car1 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
return 1;
}
{
int i, j, len;
char *tmp;
struct string *buffer;
if (( i = process_join_args( car2, 1, syntax )) == 0 )
return 1;
car1 = stack->values[ stack->used - i ];
if ( numberp( car1->flags ) ||
islist( car1->flags ) == 1 ||
type( car1->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_STRING );
return 1;
}
buffer = make_string();
string_append( buffer, '"' );
for( j = i - 1; j; --j )
{
struct object *item;
item = stack->values[ stack->used - j ];
tmp = item->data.atom->data.string->string;
len = item->data.atom->data.string->length;
while( len-- )
string_append( buffer, *tmp++ );
if ( j != 1 )
{
tmp = car1->data.atom->data.string->string;
len = car1->data.atom->data.string->length;
while( len-- )
string_append( buffer, *tmp++ );
}
}
stack_truncate( stack, i );
stack_push( stack, make_atom_directly_from_string( buffer->str, buffer->used ));
free( buffer );
}
return 0;
}
int apply_regexp( regex_t *regexp, char *the_string, int len, int show_offset, int first )
{
struct object **ptr = NULL;
struct string *buffer;
regmatch_t matches[ 20 ];
int result, length, i;
matches[ 0 ].rm_so = 0;
matches[ 0 ].rm_eo = len;
result = regexec( regexp, the_string,
( show_offset == 2 ? 1 : 20 ),
matches,
( first ? REG_STARTEND : REG_NOTBOL | REG_STARTEND ));
stack_push( stack, make_object());
setlist( ( *( struct object **)stack->top )->flags );
if ( result )
{
char err[ 80 ];
if ( result == REG_NOMATCH )
return 0;
regerror( result, regexp, err, sizeof( err ));
fprintf( stderr, "apply_regexp: regexec: %s.\n", err );
return 1;
}
switch ( show_offset )
{
case 0:
ptr = &( *( struct object **)stack->top )->data.head;
break;
case 1:
( *( struct object **)stack->top )->data.head =
make_atom_from_number( matches[ 0 ].rm_so );
( *( struct object **)stack->top )->data.head->next =
make_atom_from_number( matches[ 0 ].rm_eo );
ptr = &( *( struct object **)stack->top )->data.head->next->next;
break;
case 2:
( *( struct object **)stack->top )->data.head =
make_atom_from_number( matches[ 0 ].rm_so );
( *( struct object **)stack->top )->data.head->next =
make_atom_from_number( matches[ 0 ].rm_eo );
return 0;
}
buffer = make_string();
for( i = 0; i < 20; ++i )
{
if ( matches[ i ].rm_so >= 0 )
{
int j;
length = matches[ i ].rm_so + matches[ i ].rm_eo - matches[ i ].rm_so;
for( j = matches[ i ].rm_so; j < length; ++j )
string_append( buffer, the_string[ j ] );
}
*ptr = make_atom_from_string( buffer->str, buffer->used );
( *ptr )->next = NULL;
ptr = &( *ptr )->next;
string_truncate( buffer );
}
string_free( buffer );
return 0;
}
int do_matches( char *syntax, struct object *args )
{
struct object *car1, *car2;
stack_push( arg_stack, ( void *)ERR_REGEXP );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
return apply_regexp( car1->data.atom->data.regexp,
car2->data.atom->data.string->string,
car2->data.atom->data.string->length,
0,
1 );
}
int do_match( char *syntax, struct object *args )
{
struct object *car1, *car2;
stack_push( arg_stack, ( void *)ERR_REGEXP );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
return apply_regexp( car1->data.atom->data.regexp,
car2->data.atom->data.string->string,
car2->data.atom->data.string->length,
2,
1 );
}
int add_char( struct string *buffer, char *ptr, int change_case )
{
switch( change_case )
{
case 0:
string_append( buffer, *ptr );
break;
case 1:
string_append( buffer, toupper( *ptr ));
change_case = 0;
break;
case 2:
string_append( buffer, toupper( *ptr ));
break;
case 3:
string_append( buffer, tolower( *ptr ));
change_case = 0;
break;
case 4:
string_append( buffer, tolower( *ptr ));
break;
}
return change_case;
}
int do_substitute( char *syntax, struct object *args )
{
struct object *car1, *car2, *car3, *car4;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
car1 = args;
car2 = car1->next;
if ( car2 == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 2, -1 );
return 1;
}
car3 = car2->next;
if ( car3 == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 3, -1 );
return 1;
}
stack_push( stack, car1 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
return 1;
}
stack_push( stack, car2 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, -1 );
return 1;
}
stack_push( stack, car3 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 3, -1 );
return 1;
}
car4 = car3->next;
if ( car4 != NULL )
{
if ( car4->next != NULL )
{
print_err( ERR_MORE_ARGS, syntax, 4, -1 );
return 1;
}
stack_push( stack, car4 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 4, -1 );
return 1;
}
car4 = stack_pop( stack );
if ( islist( car4->flags ) == 1 || numberp( car4->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 4, ERR_FIXNUM );
return 1;
}
}
car3 = stack_pop( stack );
if ( islist( car3->flags ) == 1 ||
numberp( car3->flags ) ||
type( car3->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, 3, ERR_STRING );
return 1;
}
car2 = stack_pop( stack );
if ( islist( car2->flags ) == 1 ||
numberp( car2->flags ) ||
type( car2->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, 2, ERR_STRING );
return 1;
}
car1 = stack_pop( stack );
if ( islist( car1->flags ) == 1 ||
numberp( car1->flags ) ||
type( car1->data.atom->flags ) != ATOM_REGEXP )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_REGEXP );
return 1;
}
{
char *tmp1, *tmp2, *tmp3, *tmp4, *subs[ 11 ], *ptr, *old_tmp4;
struct object *obj;
struct string *buffer;
int first, arg4, len3, escape, i, begin, end, count, change_case;
regex_t *rx;
rx = car1->data.atom->data.regexp;
arg4 = ( car4 == NULL ? 1 : number( car4->data.atom ));
tmp2 = car2->data.atom->data.string->string;
tmp3 = car3->data.atom->data.string->string;
len3 = car3->data.atom->data.string->length;
tmp4 = tmp3;
change_case = 0;
buffer = make_string();
count = 0;
old_tmp4 = NULL;
first = 1;
for( ; ; )
{
if ( !first && ( tmp4 - tmp3 ) >= len3 )
break;
if ( tmp4 == old_tmp4 )
string_append( buffer, *tmp4++ );
old_tmp4 = tmp4;
if ( apply_regexp( rx, tmp4, len3 - ( tmp4 - tmp3 ), 1, first ))
return 1;
first = 0;
car1 = stack_pop( stack );
if ( car1->data.head == NULL )
break;
begin = number( car1->data.head->data.atom );
end = number( car1->data.head->next->data.atom );
car1->data.head->flags = 0;
car1->data.head->next->flags = 0;
i = 0;
for( obj = car1->data.head->next->next; obj != NULL; obj = obj->next )
{
subs[ i++ ] = obj->data.atom->data.string->string;
if ( i > 10 )
break;
}
ptr = tmp4;
if ( begin )
for( i = 0; i < begin; ++i )
string_append( buffer, *ptr++ );
escape = 0;
for( ptr = tmp2; *ptr; ++ptr )
{
char c[ 2 ];
if ( *ptr == '\\' )
{
if ( escape )
string_append( buffer, '\\' );
escape ^= 1;
continue;
}
else if ( escape )
{
c[ 0 ] = *ptr;
c[ 1 ] = '\0';
escape = 0;
if ( *ptr >= '1' && *ptr <= '9' )
{
tmp1 = subs[ atoi( c ) ];
while( *tmp1 )
{
change_case = add_char( buffer, tmp1, change_case );
++tmp1;
}
continue;
}
switch( *ptr )
{
case '0':
tmp1 = subs[ 10 ];
while( *tmp1 )
{
change_case = add_char( buffer, tmp1, change_case );
++tmp1;
}
continue;
case '&':
tmp1 = subs[ 0 ];
while( *tmp1 )
{
change_case = add_char( buffer, tmp1, change_case );
++tmp1;
}
continue;
case 't':
string_append( buffer, '\t' );
continue;
case 'b':
string_append( buffer, ' ' );
continue;
case 'U':
change_case = 2;
continue;
case 'u':
change_case = 1;
continue;
case 'L':
change_case = 4;
continue;
case 'l':
change_case = 3;
continue;
case 'e':
change_case = 0;
continue;
case '\\':
string_append( buffer, '\\' );
continue;
default:
change_case = add_char( buffer, ptr, change_case );
continue;
}
}
change_case = add_char( buffer, ptr, change_case );
}
tmp4 = &tmp4[ end ];
if ( ++count == arg4 )
break;
}
for( ptr = tmp4; *ptr; ++ptr )
change_case = add_char( buffer, ptr, change_case );
stack_push( stack, make_atom_from_string( buffer->str, buffer->used ));
string_free( buffer );
}
return 0;
}
int do_regcomp( char *syntax, struct object *args )
{
struct string *new;
char *ptr, *tmp;
regex_t *regexp;
int escape, result, len, flags;
struct object *car1, *car2, *car3;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
car1 = args;
car2 = car1->next;
car3 = NULL;
if ( car2 != NULL )
{
car3 = car2->next;
if ( car3 != NULL && car3->next != NULL )
{
print_err( ERR_MORE_ARGS, syntax, 3, -1 );
return 1;
}
}
stack_push( stack, car1 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
return 1;
}
if ( car2 != NULL )
{
stack_push( stack, car2 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, -1 );
return 1;
}
if ( car3 != NULL )
{
stack_push( stack, car3 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 3, -1 );
return 1;
}
car3 = stack_pop( stack );
if ( numberp( car3->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 3, ERR_FIXNUM );
return 1;
}
}
car2 = stack_pop( stack );
if ( numberp( car2->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 2, ERR_FIXNUM );
return 1;
}
}
car1 = stack_pop( stack );
if ( islist( car1->flags ) || numberp( car1->flags )
|| type( car1->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_STRING );
return 1;
}
ptr = car1->data.atom->data.string->string;
len = car1->data.atom->data.string->length;
escape = 0;
new = make_string();
for( ; len; --len )
{
if ( *ptr == '\\' )
{
if ( car3 == NULL || number( car3->data.atom ) == 0 )
{
escape ^= 1;
if ( !escape )
{
string_append( new, '\\' );
string_append( new, '\\' );
}
++ptr;
continue;
}
}
if ( escape )
{
switch( *ptr )
{
case 'b':
string_append( new, ' ' );
break;
case 't':
string_append( new, '\t' );
break;
case 'r':
string_append( new, '\r' );
break;
case 'n':
string_append( new, '\n' );
break;
case '>':
tmp = "[[:>:]]";
while( *tmp )
string_append( new, *tmp++ );
break;
case '<':
tmp = "[[:<:]]";
while( *tmp )
string_append( new, *tmp++ );
break;
case '?':
string_append( new, '\\' );
string_append( new, '?' );
break;
case '+':
string_append( new, '\\' );
string_append( new, '+' );
break;
case '^':
string_append( new, '\\' );
string_append( new, '^' );
break;
case '$':
string_append( new, '\\' );
string_append( new, '$' );
break;
case '.':
string_append( new, '\\' );
string_append( new, '.' );
break;
case '[':
string_append( new, '\\' );
string_append( new, '[' );
break;
case '(':
string_append( new, '\\' );
string_append( new, '(' );
break;
case ')':
string_append( new, '\\' );
string_append( new, ')' );
break;
case '|':
string_append( new, '\\' );
string_append( new, '|' );
break;
case '{':
string_append( new, '\\' );
string_append( new, '{' );
break;
case '*':
string_append( new, '\\' );
string_append( new, '*' );
break;
default:
string_append( new, *ptr );
}
}
else
string_append( new, *ptr );
++ptr;
escape = 0;
}
regexp = ( regex_t *)memory( sizeof( regex_t ));
regexp->re_endp = &new->str[ new->used ];
flags = REG_EXTENDED | REG_PEND;
if ( car2 != NULL && number( car2->data.atom ) )
flags |= REG_ICASE;
if ( car3 != NULL && number( car3->data.atom ) )
{
flags &= ~REG_EXTENDED;
flags |= REG_NOSPEC;
}
result = regcomp( regexp, new->str, flags );
if ( result )
{
char err[ 83 ];
regerror( result, regexp, err, sizeof( err ) - 1 );
free( regexp );
string_free( new );
stack_push( stack, make_atom_from_string( err, strlen( err )));
return 0;
}
string_free( new );
stack_push( stack, make_atom_from_regexp( regexp ));
return 0;
}
int do_sort( char *syntax, struct object *args )
{
struct object *ptr, *result, **ptr2;
struct stack *items;
int i, first = 1, type = 0;
for( i = 1, ptr = args; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, i, -1 );
return 1;
}
result = *( struct object **)stack->top;
if ( islist( result->flags ))
{
print_err( ERR_ARG_TYPE, syntax, i, ERR_ATOM );
return 1;
}
if ( numberp( result->flags ) == 0 &&
type( result->data.atom->flags ) != ATOM_STRING )
{
fprintf( stderr, "%s: arguments must either be all strings "
"or all numbers.\n", syntax );
return 1;
}
if ( first && numberp( result->flags ) == 0 )
type = 1;
first = 0;
if ( type )
{
if ( numberp( result->flags ) ||
type( result->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, i, ERR_STRING );
return 1;
}
}
else
{
if ( numberp( result->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, i, ERR_FIXNUM );
return 1;
}
}
}
items = make_stack();
while( --i )
{
result = stack_pop( stack );
stack_push( items, ( type ? ( struct object *)result->data.atom->data.string :
( struct object *)number( result->data.atom )));
}
result = make_object();
setlist( result->flags );
stack_push( stack, result );
ptr2 = &result->data.head;
if ( type )
{
qsort( items->values, items->used, sizeof( void * ),
compare_strings );
for( i = 0; i < items->used; ++i )
{
*ptr2 = make_atom_from_string(
(( struct lstring *)items->values[ i ] )->string,
(( struct lstring *)items->values[ i ] )->length );
( *ptr2 )->next = NULL;
ptr2 = &( *ptr2 )->next;
}
}
else
{
qsort( items->values, items->used, sizeof( void * ),
compare_numbers );
for( i = 0; i < items->used; ++i )
{
*ptr2 = make_atom_from_number( ( int )items->values[ i ] );
( *ptr2 )->next = NULL;
ptr2 = &( *ptr2 )->next;
}
}
stack_free( items );
return 0;
}
int do_sortcar( char *syntax, struct object *args )
{
struct object *car, *ptr, **ptr2 = NULL;
int type = 0, i, first = 1;
stack_push( arg_stack, ( void *)ERR_LIST );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
i = 1;
for( ptr = car->data.head; ptr != NULL; ptr = ptr->next )
{
if ( islist( ptr->flags ) == 0 )
{
fprintf( stderr, "%s: list element %d is not a sublist.\n", syntax, i );
return 1;
}
if ( islist( ptr->data.head->flags ))
{
fprintf( stderr, "%s: car of sublist %d is not an atom.\n",
syntax, i );
return 1;
}
if ( first )
{
if ( numberp( ptr->data.head->flags ))
type = 0;
else if ( type( ptr->data.head->data.atom->flags ) == ATOM_STRING )
type = 1;
else
{
fprintf( stderr, "%s: the car of sublist %d is neither a number"
"nor a string.\n", syntax, i );
return 1;
}
first = 0;
}
else if ( type )
{
if ( numberp( ptr->data.head->flags ) ||
type( ptr->data.head->data.atom->flags ) != ATOM_STRING )
{
fprintf( stderr, "%s: the car of sublist %d is not a string.\n",
syntax, i );
return 1;
}
}
else
{
if ( numberp( ptr->data.head->flags ) == 0 )
{
fprintf( stderr, "%s: the car of sublist %d is not a number.\n",
syntax, i );
return 1;
}
}
++i;
}
{
struct object *result;
struct stack *items;
items = make_stack();
for( ptr = car->data.head; ptr != NULL; ptr = ptr->next )
stack_push( items, ptr );
result = make_object();
stack_push( stack, result );
setlist( result->flags );
ptr2 = &result->data.head;
if ( type )
qsort( items->values, items->used, sizeof( struct object * ),
compare_car_strings );
else
qsort( items->values, items->used, sizeof( struct object * ),
compare_car_numbers );
for( i = 0; i < items->used; ++i )
{
*ptr2 = duplicate_object( ( struct object *)items->values[ i ] );
ptr2 = &( *ptr2 )->next;
}
*ptr2 = NULL;
stack_free( items );
}
return 0;
}
int do_sortlist( char *syntax, struct object *args )
{
struct object *car, *ptr, **ptr2 = NULL;
int type = 0, i, first = 1;
stack_push( arg_stack, ( void *)ERR_LIST );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
for( i = 1, ptr = car->data.head; ptr != NULL; ptr = ptr->next, ++i )
{
if ( islist( ptr->flags ) == 1 )
{
fprintf( stderr, "%s: list element %d is not an atom.\n", syntax, i );
return 1;
}
if ( first )
{
if ( numberp( ptr->flags ))
type = 0;
else if ( type( ptr->data.atom->flags ) == ATOM_STRING )
type = 1;
else
{
fprintf( stderr, "%s: list element %d is neither a number nor a "
"string.\n", syntax, i );
return 1;
}
first = 0;
}
else if ( type )
{
if ( numberp( ptr->flags ) || type( ptr->data.atom->flags ) != ATOM_STRING )
{
fprintf( stderr, "%s: list element %d is not a string.\n",
syntax, i );
return 1;
}
}
else
{
if ( numberp( ptr->flags ) == 0 )
{
fprintf( stderr, "%s: list element %d is not a number.\n",
syntax, i );
return 1;
}
}
}
{
struct object *result;
struct stack *items;
items = make_stack();
for( ptr = car->data.head; ptr != NULL; ptr = ptr->next )
{
if ( type )
stack_push( items, ptr->data.atom->data.string );
else
stack_push( items, ( void *)number( ptr->data.atom ));
}
result = make_object();
setlist( result->flags );
stack_push( stack, result );
ptr2 = &result->data.head;
if ( type )
{
qsort( items->values, items->used, sizeof( void * ),
compare_strings );
for( i = 0; i < items->used; ++i )
{
*ptr2 = make_atom_from_string(
(( struct lstring *)items->values[ i ] )->string,
(( struct lstring *)items->values[ i ] )->length );
( *ptr2 )->next = NULL;
ptr2 = &( *ptr2 )->next;
}
}
else
{
qsort( items->values, items->used, sizeof( void * ),
compare_numbers );
for( i = 0; i < items->used; ++i )
{
*ptr2 = make_atom_from_number( ( int )items->values[ i ] );
( *ptr2 )->next = NULL;
ptr2 = &( *ptr2 )->next;
}
}
stack_free( items );
}
return 0;
}
int do_while( char *syntax, struct object *args )
{
struct object *car, *result;
int i;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
car = args;
i = stack->used;
for( ; ; )
{
CONTINUE:
stack_push( stack, car );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: evaluation of test clause failed.\n", syntax );
return 1;
}
result = stack_pop( stack );
if (( islist( result->flags ) == 1 && result->data.head == NULL ) ||
result->data.atom == NULL ||
result->data.atom == empty->data.atom )
break;
if ( args->next != NULL )
{
int j;
struct object *ptr;
for( j = 1, ptr = args->next; ptr != NULL; ptr = ptr->next, ++j )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: error evaluating body expression %d.\n",
syntax, j );
if ( next_iteration )
{
next_iteration = 0;
stop = 0;
thrown = NULL;
stack_truncate( stack, stack->used - i );
goto CONTINUE;
}
return 1;
}
stack_pop( stack );
}
}
}
stack_push( stack, result );
return 0;
}
int do_until( char *syntax, struct object *args )
{
struct object *car, *result;
int i;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
car = args;
i = stack->used;
for( ; ; )
{
stack_push( stack, car );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: evaluation of test clause failed.\n", syntax );
return 1;
}
result = stack_pop( stack );
if ( !(( islist( result->flags ) == 1 && result->data.head == NULL ) ||
result->data.atom == NULL ||
result->data.atom == empty->data.atom ))
break;
if ( args->next != NULL )
{
if ( do_progn( syntax, car->next ))
{
if ( !stop )
fprintf( stderr, "%s: evaluation of body failed.\n", syntax );
if ( next_iteration )
{
next_iteration = 0;
stop = 0;
thrown = NULL;
stack_truncate( stack, stack->used - i );
continue;
}
return 1;
}
stack_pop( stack );
}
}
stack_push( stack, result );
return 0;
}
int do_do( char *syntax, struct object *args )
{
struct object *result = NULL;
int i;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
i = stack->used;
for( ; ; )
{
int j;
struct object *ptr;
CONTINUE:
for( j = 1, ptr = args; ptr != NULL; ptr = ptr->next, ++j )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: error evaluating body expression %d.\n",
syntax, j );
if ( next_iteration )
{
next_iteration = 0;
stop = 0;
thrown = NULL;
stack_truncate( stack, stack->used - i );
goto CONTINUE;
}
return 1;
}
result = stack_pop( stack );
}
if (( islist( result->flags ) == 1 && result->data.head == NULL ) ||
result->data.atom == NULL ||
result->data.atom == empty->data.atom )
break;
}
stack_push( stack, result );
return 0;
}
int do_throw( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
thrown = stack_pop( stack );
stop = 1;
return 1;
}
int do_catch( char *syntax, struct object *args )
{
int i;
i = stack->used;
if ( do_progn( syntax, args ))
{
if ( !stop )
{
fprintf( stderr, "%s: evaluation of body failed.\n", syntax );
return 1;
}
else if ( thrown != NULL )
{
stack_truncate( stack, stack->used - i );
stack_push( stack, thrown );
thrown = NULL;
stop = 0;
}
else
return 1;
}
return 0;
}
int do_die( char *syntax, struct object *args )
{
if ( args != NULL )
do_warn( syntax, args );
stop = 1;
next_iteration = 0;
thrown = NULL;
return 1;
}
int do_stringify( char *syntax, struct object *args )
{
int i, len;
struct object *item, *result, *ptr;
struct stack *myatoms;
char *tmp;
struct string *final;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
for( i = 1, item = args; item != NULL; item = item->next, ++i )
{
stack_push( stack, item );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, i, -1 );
return 1;
}
result = *( struct object **)stack->top;
if ( islist( result->flags ) == 1 )
{
print_err( ERR_ARG_TYPE, syntax, i, ERR_ATOM );
return 1;
}
}
final = make_string();
myatoms = make_stack();
while( --i )
stack_push( myatoms, stack_pop( stack ));
while( myatoms->used )
{
ptr = stack_pop( myatoms );
if ( numberp( ptr->flags ) )
{
char buffer[ 64 ];
snprintf( buffer, sizeof( buffer ), "%i", number( ptr->data.atom ));
tmp = buffer;
while( *tmp )
string_append( final, *tmp++ );
}
else if ( type( ptr->data.atom->flags ) == ATOM_STRING )
{
tmp = ptr->data.atom->data.string->string;
len = ptr->data.atom->data.string->length;
while( len-- )
string_append( final, *tmp++ );
}
else
{
tmp = ptr->data.atom->syntax;
len = ptr->data.atom->len;
while( len-- )
string_append( final, *tmp++ );
}
}
stack_push( stack, make_atom_from_string( final->str, final->used ));
stack_free( myatoms );
string_free( final );
return 0;
}
int do_digitize( char *syntax, struct object *args )
{
struct object *car;
int i;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
i = atoi( car->data.atom->data.string->string );
stack_push( stack, make_atom_from_number( i ));
return 0;
}
int do_intern( char *syntax, struct object *args )
{
struct object *car;
char *ptr;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
ptr = car->data.atom->data.string->string;
if ( *ptr == '\0' )
{
fprintf( stderr, "%s: empty string passed as argument.\n", syntax );
return 1;
}
else if ( *ptr < 58 && *ptr > 47 )
{
fprintf( stderr, "%s: symbols cannot start with a numerical character.\n",
syntax );
return 1;
}
for( ++ptr; *ptr; ++ptr )
if ( *ptr < 48 ||
*ptr > 122 ||
( *ptr > 57 && *ptr < 65 ) ||
( *ptr > 90 && *ptr < 95 ) ||
( *ptr > 95 && *ptr < 97 ))
{
fprintf( stderr, "%s: non-symbol character in argument.\n",
syntax );
return 1;
}
stack_push( stack, make_atom_from_symbol( car->data.atom->data.string->string ));
return 0;
}
int do_additive( char *syntax, struct object *args, int multiply )
{
struct object *ptr, *result;
int i, total;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
total = multiply;
i = 1;
for( ptr = args; ptr != NULL; ptr = ptr->next )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, i, -1 );
return 1;
}
result = stack_pop( stack );
if ( islist( result->flags ) == 1 ||
numberp( result->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, i, ERR_FIXNUM );
return 1;
}
if ( multiply )
total *= number( result->data.atom );
else
total += number( result->data.atom );
++i;
}
stack_push( stack, make_atom_from_number( total ));
return 0;
}
int do_add( char *syntax, struct object *args )
{
return do_additive( syntax, args, 0 );
}
int do_multiply( char *syntax, struct object *args )
{
return do_additive( syntax, args, 1 );
}
int do_subtractive( char *syntax, struct object *args, int divide )
{
struct object *car1, *car2;
int i1, i2, result = 0;
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
i1 = number( car1->data.atom );
i2 = number( car2->data.atom );
if ( divide && ! i2 )
{
fprintf( stderr, "%s: attempted division by zero.\n", syntax );
return 1;
}
switch( divide )
{
case 0:
result = i1 - i2;
break;
case 1:
result = i1 / i2;
break;
case 2:
result = i1 - ( i2 * ( i1 / i2 ));
}
stack_push( stack, make_atom_from_number( result ));
return 0;
}
int do_subtract( char *syntax, struct object *args )
{
return do_subtractive( syntax, args, 0 );
}
int do_divide( char *syntax, struct object *args )
{
return do_subtractive( syntax, args, 1 );
}
int do_modulo( char *syntax, struct object *args )
{
return do_subtractive( syntax, args, 2 );
}
int do_comparative( char *syntax, struct object *args, int what )
{
int result = 0, i1, i2;
struct object *car1, *car2;
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
i1 = number( car1->data.atom );
i2 = number( car2->data.atom );
switch( what )
{
case 0:
result = ( i1 > i2 );
break;
case 1:
result = ( i1 >= i2 );
break;
case 2:
result = ( i1 < i2 );
break;
case 3:
result = ( i1 <= i2 );
}
stack_push( stack, make_atom_from_number( result ));
return 0;
}
int do_lesser( char *syntax, struct object *args )
{
return do_comparative( syntax, args, 2 );
}
int do_lesser_or_eq( char *syntax, struct object *args )
{
return do_comparative( syntax, args, 3 );
}
int do_greater( char *syntax, struct object *args )
{
return do_comparative( syntax, args, 0 );
}
int do_greater_or_eq( char *syntax, struct object *args )
{
return do_comparative( syntax, args, 1 );
}
int do_abs( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
stack_push( stack, make_atom_from_number( abs( number( car->data.atom ))));
return 0;
}
int do_char( char *syntax, struct object *args )
{
struct object *car;
char s[ 2 ];
int i;
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
i = number( car->data.atom );
if ( i < 0 || i > 255 )
{
fprintf( stderr, "%s: argument out of range: %d\n",
syntax, i );
return 1;
}
s[ 0 ] = ( char )i;
s[ 1 ] = '\0';
stack_push( stack, make_atom_from_string( s, 1 ));
return 0;
}
int do_code( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
if ( car->data.atom->data.string->length == 0 )
{
fprintf( stderr, "%s: argument is empty string.\n", syntax );
return 1;
}
stack_push( stack,
make_atom_from_number( ( unsigned char)car->data.atom->data.string->string[ 0 ] ));
return 0;
}
int do_open( char *syntax, struct object *args )
{
DB *new_db;
mode_t mode;
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
mode = getmode( setmode( "0600" ), 0 );
AGAIN:
if (( new_db = dbopen( NULL, O_EXCL | O_EXLOCK | O_RDWR | O_CREAT, mode,
DB_RECNO, NULL )) == NULL )
{
if ( errno == EINTR )
goto AGAIN;
fprintf( stderr, "%s: %s.\n", syntax, strerror( errno ));
return 1;
}
stack_push( buffer_stack, new_db );
buffer = new_db;
bookmarks = ( struct hash_elt **)memory( HASH_SIZE * sizeof( struct hash_elt * ));
bzero( bookmarks, ( HASH_SIZE * sizeof( struct hash_elt * )));
stack_push( bookmark_stack, bookmarks );
stack_push( stack, make_atom_from_number( buffer_stack->used - 1 ));
return 0;
}
int do_close( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer has been opened.\n", syntax );
return 1;
}
if ( buffer->close( buffer ) )
{
fprintf( stderr, "%s: db->close: %s", syntax, strerror( errno ));
return 1;
}
else
{
int i;
for( i = 0; i < buffer_stack->used; ++i )
if ( buffer_stack->values[ i ] == buffer )
{
buffer_stack->values[ i ] = NULL;
hash_free( bookmark_stack->values[ i ] );
free( bookmark_stack->values[ i ] );
bookmark_stack->values[ i ] = NULL;
break;
}
buffer = NULL;
for( i = buffer_stack->used - 1; i >= 0; --i )
{
buffer = ( DB *)buffer_stack->values[ i ];
if ( buffer != NULL )
{
bookmarks = bookmark_stack->values[ i ];
break;
}
}
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_insert( char *syntax, struct object *args )
{
struct object *car1, *car2, *car3;
int arg3, flag = 0, real_line;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)3 );
if ( check_args( syntax, args ))
return 1;
car3 = stack_pop( stack );
car2 = stack_pop( stack );
car1 = stack_pop( stack );
key_data = number( car1->data.atom );
real_line = key_data;
if ( key_data < 0 )
{
fprintf( stderr, "%s: argument 1 < 0.\n", syntax );
return 1;
}
arg3 = number( car3->data.atom );
if ( arg3 == 0 )
flag = R_SETCURSOR;
else if ( arg3 > 0 )
{
flag = R_IAFTER;
real_line += 1;
}
else if ( arg3 < 0 )
{
flag = R_IBEFORE;
real_line -= 1;
}
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
dbt_value.data = car2->data.atom->data.string->string;
dbt_value.size = car2->data.atom->data.string->length + 1;
if ( buffer->put( buffer, &dbt_key, &dbt_value, flag ) < 0 )
{
fprintf( stderr, "%s: db->put: %s.\n", syntax, strerror( errno ));
return 1;
}
else
stack_push( stack, make_atom_from_number( 1 ));
if ( real_line == key_data )
delete_bookmarks( real_line, real_line );
else
adjust_bookmarks( real_line, 1 );
return 0;
}
int do_delete( char *syntax, struct object *args )
{
struct object *car;
int result, arg1;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
arg1 = number( car->data.atom );
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
key_data = arg1;
if (( result = buffer->del( buffer, &dbt_key, 0 )) < 0 )
{
fprintf( stderr, "%s: delete: db->del: %s.\n", syntax, strerror( errno ));
stack_push( stack, make_atom_from_number( 0 ));
return 1;
}
else if ( result )
{
fprintf( stderr, "%s: index does not exist: %d.\n", syntax,
key_data );
stack_push( stack, make_atom_from_number( 0 ));
return 1;
}
delete_bookmarks( key_data, key_data );
adjust_bookmarks( key_data, -1 );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_lastline( char *syntax, struct object *args )
{
int result;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if (( result = buffer->seq( buffer, &dbt_key, &dbt_value, R_LAST )) == -1 )
{
fprintf( stderr, "%s: db->seq: %s.\n", syntax, strerror( errno ));
stack_push( stack, make_atom_from_number( 0 ));
}
else if ( result == 1 )
stack_push( stack, make_atom_from_number( 0 ));
else
stack_push( stack, make_atom_from_number( *( int *)dbt_key.data ));
return 0;
}
int do_retrieve( char *syntax, struct object *args )
{
struct object *car;
int result;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
key_data = number( car->data.atom );
if ( key_data <= 0 )
{
fprintf( stderr, "%s: index <= 0.\n", syntax );
return 1;
}
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if (( result = buffer->get( buffer, &dbt_key, &dbt_value, 0 )) < 0 )
{
fprintf( stderr, "%s: db->get: %s.\n", syntax, strerror( errno ));
return 1;
}
else if ( result == 1 )
{
fprintf( stderr, "%s: db->get: key does not exist.\n", syntax );
return 1;
}
stack_push( stack, make_atom_from_string( dbt_value.data, dbt_value.size - 1 ));
return 0;
}
int exchange_data( char *syntax, int fd, int begin, int end, int pid )
{
struct string *s;
char *ptr = NULL;
int i, j, before, out, result, flags;
fd_set in_set, out_set;
s = make_string();
j = end;
i = begin;
before = end;
if ( end )
out = 1;
else
{
j = begin;
before = begin;
shutdown( fd, SHUT_WR );
out = 0;
}
if (( flags = fcntl( fd, F_GETFL, 0 ) ) < 0 )
{
fprintf( stderr, "%s: fcntl(): %s.\n", syntax, strerror( errno ));
return 1;
}
if ( fcntl( fd, F_SETFL, flags | O_NONBLOCK ) < 0 )
{
fprintf( stderr, "%s: fcntl(): %s.\n", syntax, strerror( errno ));
return 1;
}
for( ; ; )
{
char c[ 128 ];
FD_ZERO( &in_set );
FD_ZERO( &out_set );
FD_SET( fd, &in_set );
if ( out )
FD_SET( fd, &out_set );
result = select( fd + 1, &in_set, &out_set, NULL, NULL );
if ( result < 0 )
{
if ( errno == EINTR || errno == EWOULDBLOCK )
continue;
( out ? close( fd ) : shutdown( fd, SHUT_RD ) );
string_free( s );
fprintf( stderr, "%s: select: %s.\n", syntax, strerror( errno ));
return 1;
}
if ( FD_ISSET( fd, &in_set ))
{
result = read( fd, c, sizeof( c ) - 1 );
if ( result < 0 )
{
if ( errno == EINTR || errno == EWOULDBLOCK )
continue;
( out ? close( fd ) : shutdown( fd, SHUT_RD ) );
string_free( s );
fprintf( stderr, "%s: read: %s.\n", syntax, strerror( errno ));
return 1;
}
else if ( result == 0 )
{
( out ? close( fd ) : shutdown( fd, SHUT_RD ));
break;
}
else
{
char *ptr2;
c[ result ] = '\0';
for( ptr2 = c; *ptr2; ++ptr2 )
if ( *ptr2 == '\n' )
{
string_append( s, *ptr2 );
key_data = j++;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
dbt_value.data = s->str;
dbt_value.size = s->used + 1;
if ( buffer->put( buffer, &dbt_key, &dbt_value, R_IAFTER ) < 0 )
{
fprintf( stderr, "%s: db->put: %s.\n", syntax, strerror( errno ));
string_free( s );
( out ? close( fd ) : shutdown( fd, SHUT_RD ));
return 1;
}
string_truncate( s );
}
else
string_append( s, *ptr2 );
}
}
if ( out && FD_ISSET( fd, &out_set ))
{
if ( ptr == NULL || *ptr == '\0' )
{
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
key_data = i++;
if (( result = buffer->get( buffer, &dbt_key, &dbt_value, 0 )) < 0 )
{
( out ? close( fd ) : shutdown( fd, SHUT_RD ));
string_free( s );
fprintf( stderr, "%s: db->get: %s.\n", syntax, strerror( errno ));
return 1;
}
else if ( result == 1 )
{
( out ? close( fd ) : shutdown( fd, SHUT_RD ));
string_free( s );
fprintf( stderr, "%s: db->get: key does not exist.\n", syntax );
return 1;
}
ptr = dbt_value.data;
}
result = write( fd, ptr, strlen( ptr ));
if ( result < 0 )
{
if ( errno == EINTR || errno == EWOULDBLOCK )
continue;
close( fd );
string_free( s );
fprintf( stderr, "%s: write: %s.\n", syntax, strerror( errno ));
return 1;
}
ptr += result;
if ( *ptr == '\0' )
{
if ( i > end )
{
shutdown( fd, SHUT_WR );
ptr = NULL;
out = 0;
}
}
}
}
if ( s->used )
{
key_data = j++;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
dbt_value.data = s->str;
dbt_value.size = s->used + 1;
if ( buffer->put( buffer, &dbt_key, &dbt_value, R_IAFTER ) < 0 )
{
fprintf( stderr, "%s: db->put: %s.\n", syntax, strerror( errno ));
string_free( s );
return 1;
}
}
waitpid( pid, NULL, 0 );
string_free( s );
if ( end && j > end )
{
delete_bookmarks( begin, end );
adjust_bookmarks( end, ( begin - end ) - 1 );
}
if ( j > end )
adjust_bookmarks( ( end ? begin : begin - 1 ), j - end );
if ( end && j > end )
{
for( i = begin; i <= end; ++i )
{
key_data = begin;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if ( buffer->del( buffer, &dbt_key, 0 ))
{
fprintf( stderr, "%s: db->del: %s.\n", syntax, strerror( errno ));
return 1;
}
}
}
stack_push( stack, make_atom_from_number( j - before ));
return 0;
}
int do_filter( char *syntax, struct object *args )
{
struct object *car1, *car2, *car3;
char *exec_args[ 4 ];
int pid, beginning, ending, result;
int fd[ 2 ];
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)3 );
if ( check_args( syntax, args ))
return 1;
car3 = stack_pop( stack );
car2 = stack_pop( stack );
car1 = stack_pop( stack );
beginning = number( car1->data.atom );
ending = number( car2->data.atom );
if ( beginning > ending )
{
int temp = beginning;
beginning = ending;
ending = temp;
}
exec_args[ 0 ] = "/bin/sh";
exec_args[ 1 ] = "-c";
exec_args[ 2 ] = car3->data.atom->data.string->string;
exec_args[ 3 ] = NULL;
if ( socketpair( PF_LOCAL, SOCK_STREAM, 0, fd ))
{
fprintf( stderr, "%s: socketpair: %s.\n", syntax, strerror( errno ));
return 1;
}
switch( pid = fork() )
{
case -1:
fprintf( stderr, "%s: fork: %s.\n", syntax, strerror( errno ));
return 1;
case 0:
if ( dup2( fd[ 0 ], 0 ) < 0 ||
dup2( fd[ 0 ], 1 ) < 0 )
{
fprintf( stderr, "%s (child): dup2: %s.\n", syntax, strerror( errno ));
_exit( 1 );
}
close( fd[ 0 ] );
close( fd[ 1 ] );
execv( exec_args[ 0 ], exec_args );
_exit( 1 );
default:
close( fd[ 0 ] );
}
result = exchange_data( syntax, fd[ 1 ], beginning, ending, pid );
return result;
}
int do_write( char *syntax, struct object *args )
{
struct object *car1, *car2, *car3, *car4, *car5;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
car1 = args;
car2 = car1->next;
if ( car2 == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 2, -1 );
return 1;
}
car3 = car2->next;
if ( car3 == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 3, -1 );
return 1;
}
car4 = car3->next;
if ( car4 == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 4, -1 );
return 1;
}
car5 = car4->next;
if ( car5 != NULL && car5->next != NULL )
{
print_err( ERR_MORE_ARGS, syntax, 5, -1 );
return 1;
}
stack_push( stack, car1 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
return 1;
}
stack_push( stack, car2 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, -1 );
return 1;
}
stack_push( stack, car3 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 3, -1 );
return 1;
}
stack_push( stack, car4 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 4, -1 );
return 1;
}
if ( car5 != NULL )
{
stack_push( stack, car5 );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 5, -1 );
return 1;
}
car5 = stack_pop( stack );
if ( islist( car5->flags ) == 1 ||
numberp( car5->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 5, ERR_FIXNUM );
return 1;
}
}
car4 = stack_pop( stack );
if ( islist( car4->flags ) == 1 ||
numberp( car4->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 4, -1 );
return 1;
}
car3 = stack_pop( stack );
if ( islist( car3->flags ) == 1 ||
numberp( car3->flags ) ||
type( car3->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, 3, -1 );
return 1;
}
car2 = stack_pop( stack );
if ( islist( car2->flags ) == 1 ||
numberp( car2->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 2, -1 );
return 1;
}
car1 = stack_pop( stack );
if ( islist( car1->flags ) == 1 ||
numberp( car1->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, -1 );
return 1;
}
{
char *name, *ptr;
mode_t mode;
int arg1, arg2, fd, i, flags, result, escape, create_empty;
arg1 = number( car1->data.atom );
arg2 = number( car2->data.atom );
create_empty = 0;
if ( !arg1 && !arg2 )
create_empty = 1;
escape = 0;
name = car3->data.atom->data.string->string;
for( ptr = name; *ptr; ++ptr )
{
if ( *ptr == '\\' )
{
escape ^= 1;
continue;
}
if ( escape && ( *ptr == 'b' || *ptr == 't' ))
{
char *d = ptr;
*( ptr - 1) = ( *ptr == 't' ? '\t' : ' ' );
++ptr;
bcopy( ptr, d, strlen( ptr ) + 1 );
ptr -= 2;
}
escape = 0;
}
if ( car5 == NULL || number( car5->data.atom ) == 0 )
flags = ( O_CREAT | O_WRONLY );
else
flags = ( O_CREAT | O_APPEND | O_WRONLY );
if ( number( car4->data.atom ) == 1 )
flags |= O_EXLOCK | O_NONBLOCK;
mode = getmode( setmode( "0600" ), 0 );
AGAIN:
if (( fd = open( name, flags, mode )) < 0 )
{
if ( errno == EINTR )
goto AGAIN;
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
/*
* Truncation must performed AFTER opening the file, because if
* specified by the O_TRUNC flag to open(), the file will be cleared,
* even if the function fails due to the existence of an exclusive
* lock for the file. This is correct, but stupid, UNIX semantics.
*/
if ( car5 == NULL || number( car5->data.atom ) == 0 )
if ( ftruncate( fd, 0 ))
{
close( fd );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
if ( create_empty )
stack_push( stack, make_atom_from_number( 0 ));
else
{
char output_buffer[ 102400 ], *ptr;
int room = sizeof( output_buffer );
if ( arg1 > arg2 )
{
int tmp;
tmp = arg1;
arg1 = arg2;
arg2 = tmp;
}
ptr = output_buffer;
for( i = arg1; i <= arg2; ++i )
{
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
key_data = i;
if (( result = buffer->get( buffer, &dbt_key, &dbt_value, 0 )) < 0 )
{
close( fd );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
else if ( result == 1 )
{
close( fd );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
if (( room - ( int )( dbt_value.size - 1 )) < 0 )
{
if ( write( fd, output_buffer, ptr - output_buffer ) < 0 )
{
close( fd );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
ptr = output_buffer;
room = sizeof( output_buffer );
}
bcopy( dbt_value.data, ptr, dbt_value.size - 1 );
ptr += dbt_value.size - 1;
room -= dbt_value.size - 1;
}
if ( write( fd, output_buffer, ptr - output_buffer ) < 0 )
{
close( fd );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( stack, make_atom_from_number( arg2 - arg1 + 1 ));
}
close( fd );
}
return 0;
}
int do_read( char *syntax, struct object *args )
{
struct object *car1, *car2;
struct string *s;
int fd, arg1, i, escape, flags, count = 0, altered = 0;
char *name, *ptr;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
arg1 = number( car1->data.atom );
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if ( buffer->seq( buffer, &dbt_key, &dbt_value, R_LAST ) == -1 )
{
fprintf( stderr, "%s: db->seq: %s.\n", syntax, strerror( errno ));
stack_push( stack, make_atom_from_number( 0 ));
}
if ( *( int *)dbt_key.data )
{
if ( arg1 )
{
flags = R_IAFTER;
altered = arg1;
}
else
{
flags = R_IBEFORE;
altered = 0;
}
}
else
flags = R_SETCURSOR;
key_data = ( arg1 ? arg1 : 1 );
name = car2->data.atom->data.string->string;
escape = 0;
for( ptr = name; *ptr; ++ptr )
{
if ( *ptr == '\\' )
{
escape ^= 1;
continue;
}
if ( escape && ( *ptr == 'b' || *ptr == 't' ))
{
char *d = ptr;
*( ptr - 1) = ( *ptr == 't' ? '\t' : ' ' );
++ptr;
bcopy( ptr, d, strlen( ptr ) + 1 );
ptr -= 2;
}
escape = 0;
}
AGAIN:
if (( fd = open( name, O_RDONLY )) < 0 )
{
if ( errno == EINTR )
goto AGAIN;
switch( errno )
{
case ENOENT:
stack_push( stack, make_atom_from_number( -1 ));
break;
case EACCES:
stack_push( stack, make_atom_from_number( -2 ));
break;
default:
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
break;
}
return 0;
}
s = make_string();
for( i = 0; ; ++i )
{
int result;
char *ptr;
char input_buffer[ 102400 ];
READ:
result = read( fd, input_buffer, sizeof( input_buffer ) - 1 );
if ( result < 0 )
{
fprintf( stderr, "%s: read: %s.\n", syntax, strerror( errno ));
break;
}
else if ( result == 0 )
{
if ( !count && s->used )
++count;
if ( s->used )
{
dbt_value.data = s->str;
dbt_value.size = s->used + 1;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if ( buffer->put( buffer, &dbt_key, &dbt_value, flags ) < 0 )
{
fprintf( stderr, "%s: db->put: %s.\n", syntax,
strerror( errno ));
string_free( s );
close( fd );
return 1;
}
}
break;
}
else
input_buffer[ result ] = '\0';
ptr = input_buffer;
do
{
char *ptr2, *tmp;
ptr2 = ptr;
if (( ptr = strchr( ptr, '\n' )) == NULL )
{
tmp = ptr2;
while( *tmp )
string_append( s, *tmp++ );
goto READ;
}
*ptr = '\0';
tmp = ptr2;
while( *tmp )
string_append( s, *tmp++ );
string_append( s, '\n' );
dbt_value.data = s->str;
dbt_value.size = s->used + 1;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if ( buffer->put( buffer, &dbt_key, &dbt_value, flags ) < 0 )
{
fprintf( stderr, "%s: db->put: %s.\n", syntax,
strerror( errno ));
string_free( s );
close( fd );
return 1;
}
string_truncate( s );
++count;
++key_data;
}
while( *++ptr );
}
string_free( s );
close( fd );
adjust_bookmarks( altered, count );
stack_push( stack, make_atom_from_number( count ));
return 0;
}
int do_empty( char *syntax, struct object *args )
{
int i, last;
struct stack *keys;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if (( i = buffer->seq( buffer, &dbt_key, &dbt_value, R_LAST )) == 1 )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
else if ( i < 0 )
{
fprintf( stderr, "%s: db->seq: %s.\n", syntax, strerror( errno ));
return 1;
}
last = *( int *)dbt_key.data;
if ( last == 0 )
{
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
keys = get_hash_keys( bookmarks );
for( i = 0; i < keys->used; ++i )
insert_elt( bookmarks, ( int )keys->values[ i ], ( struct object *)-1 );
stack_free( keys );
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
key_data = 1;
for( i = 1; i <= last; ++i )
{
int result;
if (( result = buffer->del( buffer, &dbt_key, 0 )) < 0 )
{
fprintf( stderr, "%s: db->del: %s.\n", syntax, strerror( errno ));
return 1;
}
else if ( result )
{
fprintf( stderr, "%s: index does not exist: %d.\n", syntax, i );
return 1;
}
}
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_slice( char *syntax, struct object *args )
{
struct object *car1, *car2, *car3, *car4, *car5;
int arg1, arg2, arg3, arg4, arg5;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)5 );
if ( check_args( syntax, args ))
return 1;
car5 = stack_pop( stack );
car4 = stack_pop( stack );
car3 = stack_pop( stack );
car2 = stack_pop( stack );
car1 = stack_pop( stack );
arg1 = number( car1->data.atom );
arg2 = number( car2->data.atom );
arg3 = number( car3->data.atom );
arg4 = number( car4->data.atom );
arg5 = number( car5->data.atom );
if ( arg4 <= 0 )
{
fprintf( stderr, "%s: tabsize specifier <= 0.\n", syntax );
return 1;
}
{
struct string *s = NULL, *e = NULL;
char *ptr;
recno_t i;
int offset, *offsets = NULL, result;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
key_data = arg1;
if (( result = buffer->get( buffer, &dbt_key, &dbt_value, 0 )) < 0 )
{
fprintf( stderr, "%s: db->get: %s.\n", syntax, strerror( errno ));
return 1;
}
else if ( result == 1 )
{
fprintf( stderr, "%s: db->get: key does not exist.\n", syntax );
return 1;
}
if ( dbt_value.size == 0 )
{
if ( arg5 )
{
struct object *c1, *c2;
c1 = make_atom_from_number( 0 );
c2 = make_atom_from_number( 0 );
c1->next = c2;
stack_push( stack, c1 );
return 0;
}
stack_push( stack, make_atom_from_string( "", 0 ));
return 0;
}
if ( arg5 && dbt_value.size > 1 )
offsets = ( int *)memory( sizeof( int ) * ( dbt_value.size - 1 ));
else
s = make_string();
e = make_string();
if ( dbt_value.size > 1 )
{
ptr = ( char *)dbt_value.data;
offset = 0;
for( i = 0; i < dbt_value.size - 1; ++i )
{
if ( *ptr == '\t' )
{
int spaces;
spaces = arg4 - ( i + offset ) % arg4;
offset += spaces - 1;
if ( !arg5 )
while( spaces-- )
string_append( e, ' ' );
}
else if ( !arg5 )
string_append( e, *ptr );
++ptr;
if ( arg5 )
offsets[ i ] = offset;
}
}
if ( arg5 )
{
struct object *result;
int length;
result = make_object();
stack_push( stack, result );
setlist( result->flags );
length = ( dbt_value.size - 1 ) - arg2;
if ( arg3 )
length = MIN( arg3, length );
result->data.head = make_atom_from_number( length );
result->data.head->next =
make_atom_from_number(( length ? offsets[ --length ] : 0 ));
if ( dbt_value.size > 1 )
free( offsets );
}
else
{
if ( arg2 >= e->used )
{
stack_push( stack, make_atom_from_string( "", 0 ));
string_free( s );
string_free( e );
return 0;
}
ptr = &e->str[ arg2 ];
if ( arg3 )
arg3 += arg2;
result = ( arg3 ? MIN( arg3, e->used ) : e->used );
for( i = arg2; i < result; ++i )
string_append( s, *ptr++ );
stack_push( stack, make_atom_from_string( s->str, s->used ));
string_free( s );
}
string_free( e );
}
return 0;
}
int do_find( char *syntax, struct object *args )
{
struct object *car1, *car2, *car3, *car4, *car5;
char *old_ptr;
int limit, last, old_arg3, i, j, flags,
found, inc, end, start, result, old_result,
arg1, arg2, arg3, arg5;
regmatch_t matches, old_matches;
regex_t *r;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_REGEXP );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)5 );
if ( check_args( syntax, args ))
return 1;
car5 = stack_pop( stack );
car4 = stack_pop( stack );
car3 = stack_pop( stack );
car2 = stack_pop( stack );
car1 = stack_pop( stack );
arg5 = number( car5->data.atom );
arg1 = number( car1->data.atom );
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if ( buffer->seq( buffer, &dbt_key, &dbt_value, R_LAST ) == -1 )
{
fprintf( stderr, "%s: db->seq: %s.\n", syntax, strerror( errno ));
stack_push( stack, make_atom_from_number( 0 ));
}
last = *( int *)dbt_key.data;
if ( arg1 < 0 )
{
end = 0;
inc = -1;
}
else
{
end = last + 1;
inc = 1;
}
arg2 = number( car2->data.atom );
start = arg2;
arg3 = number( car3->data.atom );
found = 0;
limit = arg3;
r = car4->data.atom->data.regexp;
for( j = 0; j < 2; ++j )
{
for( i = start; i != end; i += inc )
{
char *ptr, *temp;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
key_data = i;
if (( result = buffer->get( buffer, &dbt_key, &dbt_value, 0 )) < 0 )
{
fprintf( stderr, "%s: db->get: %s.\n",
syntax, strerror( errno ));
return 1;
}
else if ( result == 1 )
{
fprintf( stderr, "%s: db->get: key does not exist: %d.\n",
syntax, i );
return 1;
}
temp = ( char *)dbt_value.data;
temp = str_dup( temp, dbt_value.size );
if (( ptr = strchr( temp, '\n' )) != NULL )
*ptr = '\0';
ptr = temp;
if ( i == arg2 &&
( arg3 < 0 || ( arg3 && arg3 > dbt_value.size - 2 )))
{
fprintf( stderr, "%s: argument 3 out of range.\n", syntax );
return 1;
}
result = REG_NOMATCH;
arg3 = 0;
old_ptr = NULL;
matches.rm_eo = 0;
flags = 0;
do
{
old_arg3 = arg3;
arg3 += matches.rm_eo;
old_result = result;
old_matches = matches;
if ( ptr == old_ptr )
break;
old_ptr = ptr;
result = regexec( r, ptr, 1, &matches, flags );
if ( !result )
{
if ( i == arg2 )
{
if (( arg1 < 0 && arg3 + matches.rm_so >= limit ) ||
( arg1 > 0 && arg3 + matches.rm_so > limit ))
break;
}
else if ( arg1 > 0 )
break;
ptr += matches.rm_eo;
}
flags = REG_NOTBOL;
}
while( !result );
free( temp );
if ( arg1 < 0 )
{
result = old_result;
matches = old_matches;
arg3 = old_arg3;
}
else if ( i == arg2 )
{
if ( arg3 + matches.rm_so <= limit )
continue;
if ( limit + 1 == dbt_value.size - 1 &&
limit + 1 == arg3 + matches.rm_so )
continue;
}
if ( result )
{
if ( result == REG_NOMATCH )
continue;
{
char err[ 80 ];
regerror( result, r, err, sizeof( err ));
fprintf( stderr, "%s: regexec: %s.\n", syntax, err );
return 1;
}
}
found = 1;
goto LIST;
}
if ( !arg5 )
break;
if ( arg1 > 0 )
{
start = 1;
end = last + 1;
}
else
{
start = last;
end = 0;
}
arg2 = 0;
}
LIST:
car1 = make_object();
stack_push( stack, car1 );
setlist( car1->flags );
if ( !found )
{
car1->data.head = make_atom_from_number( 0 );
car1->data.head->next = make_atom_from_number( 0 );
car1->data.head->next->next = make_atom_from_number( 0 );
}
else
{
int len = matches.rm_eo - matches.rm_so;
if (( i == arg2 && arg1 > 0 ) || arg1 < 0 )
matches.rm_so += arg3;
if ( matches.rm_so > 0 && matches.rm_so == dbt_value.size - 1 )
--matches.rm_so;
car1->data.head = make_atom_from_number( i );
car1->data.head->next = make_atom_from_number( matches.rm_so );
car1->data.head->next->next = make_atom_from_number( len );
}
return 0;
}
int do_input( char *syntax, struct object *args )
{
struct object *car1, *car2;
int pid, pipe, arg1, last, result, escape;
char *name, *ptr;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if ( buffer->seq( buffer, &dbt_key, &dbt_value, R_LAST ) == -1 )
{
fprintf( stderr, "%s: db->seq: %s.\n", syntax, strerror( errno ));
stack_push( stack, make_atom_from_number( 0 ));
return 1;
}
last = *( int *)dbt_key.data;
arg1 = number( car1->data.atom );
if ( arg1 < 0 || arg1 > last )
{
fprintf( stderr, "%s: argument 1 out of range.\n", syntax );
return 1;
}
name = car2->data.atom->data.string->string;
escape = 0;
for( ptr = name; *ptr; ++ptr )
{
if ( *ptr == '\\' )
{
escape ^= 1;
continue;
}
if ( escape && ( *ptr == 'b' || *ptr == 't' ))
{
char *d = ptr;
*( ptr - 1) = ( *ptr == 't' ? '\t' : ' ' );
++ptr;
bcopy( ptr, d, strlen( ptr ) + 1 );
ptr -= 2;
}
escape = 0;
}
pipe = pipe_open( syntax, name, 0, 0, &pid );
if ( pipe == -1 )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
result = exchange_data( syntax, pipe, arg1, 0, pid );
return result;
}
int do_output( char *syntax, struct object *args )
{
struct object *car1, *car2, *car3;
char *name, *ptr;
int i, result, escape, arg1, arg2, pipe, pid;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)3 );
if ( check_args( syntax, args ))
return 1;
car3 = stack_pop( stack );
car2 = stack_pop( stack );
car1 = stack_pop( stack );
arg1 = number( car1->data.atom );
arg2 = number( car2->data.atom );
if ( arg1 > arg2 )
{
int tmp;
tmp = arg1;
arg1 = arg2;
arg2 = tmp;
}
name = car3->data.atom->data.string->string;
escape = 0;
for( ptr = name; *ptr; ++ptr )
{
if ( *ptr == '\\' )
{
escape ^= 1;
continue;
}
if ( escape && ( *ptr == 'b' || *ptr == 't' ))
{
char *d = ptr;
*( ptr - 1) = ( *ptr == 't' ? '\t' : ' ' );
++ptr;
bcopy( ptr, d, strlen( ptr ) + 1 );
ptr -= 2;
}
escape = 0;
}
pipe = pipe_open( syntax, name, 1, 0, &pid );
if ( pipe == -1 )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
for( i = arg1; i <= arg2; ++i )
{
int len, written;
char *current;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
key_data = i;
if (( result = buffer->get( buffer, &dbt_key, &dbt_value, 0 )) < 0 )
{
close( pipe );
waitpid( pid, NULL, 0 );
fprintf( stderr, "%s: db->get: %s.\n", syntax, strerror( errno ));
return 1;
}
else if ( result == 1 )
{
close( pipe );
waitpid( pid, NULL, 0 );
fprintf( stderr, "%s: db->get: key does not exist.\n", syntax );
return 1;
}
current = ( char *)dbt_value.data;
written = 0;
do
{
current += written;
len = strlen( current );
if (( written = write( pipe, current, len )) < 0 )
{
close( pipe );
waitpid( pid, NULL, 0 );
if ( errno == EPIPE )
{
stack_push( stack, make_atom_from_number( i - arg1 ));
return 0;
}
fprintf( stderr, "%s: %s.\n", syntax, strerror( errno ));
return 1;
}
}
while( written < len );
}
close( pipe );
waitpid( pid, NULL, 0 );
stack_push( stack, make_atom_from_number( i - arg1 ));
return 0;
}
int do_system( char *syntax, struct object *args )
{
struct object *car;
int result;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
if ( blocked )
{
do_unblock( syntax, NULL );
stack_pop( stack );
}
car = stack_pop( stack );
result = system( car->data.atom->data.string->string );
stack_push( stack, make_atom_from_number( result ));
if ( blocked )
{
do_block( syntax, NULL );
stack_pop( stack );
}
return 0;
}
int do_maxidx( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
stack_push( stack, make_atom_from_number( INT_MAX ));
return 0;
}
int do_chdir( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
if ( chdir( car->data.atom->data.string->string ))
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_boundp( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)ERR_ATOM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
if ( lookup_local( car->data.atom->id ) == NULL &&
lookup_binding( car->data.atom->id ) == NULL )
stack_push( stack, make_atom_from_number( 0 ));
else
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_buffer( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( buffer == NULL )
{
stack_push( stack, make_atom_from_number( -1 ));
return 0;
}
{
int i;
for( i = 0; i < buffer_stack->used; ++i )
if ( buffer == buffer_stack->values[ i ] )
break;
stack_push( stack, make_atom_from_number( i ));
}
return 0;
}
int do_buffers( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
{
struct object **ptr, *result;
int i;
result = make_object();
setlist( result->flags );
stack_push( stack, result );
ptr = &result->data.head;
for( i = 0; i < buffer_stack->used; ++i )
if ( buffer_stack->values[ i ] != NULL )
{
*ptr = make_atom_from_number( i );
ptr = &( *ptr )->next;
}
}
return 0;
}
int do_switch( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
int i;
car = stack_pop( stack );
i = number( car->data.atom );
if ( i < 0 )
{
fprintf( stderr, "%s: negative buffer number: %d.\n", syntax, i );
return 1;
}
if ( i > buffer_stack->used - 1 ||
buffer_stack->values[ i ] == NULL )
{
fprintf( stderr, "%s: buffer %d is not open.\n", syntax, i );
return 1;
}
buffer = ( DB *)buffer_stack->values[ i ];
bookmarks = ( struct hash_elt **)bookmark_stack->values[ i ];
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_version( char *syntax, struct object *args )
{
struct object *result;
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
result = make_object();
setlist( result->flags );
stack_push( stack, result );
result->data.head = make_atom_from_number( VERSION_MAJOR );
result->data.head->next = make_atom_from_number( VERSION_MINOR );
return 0;
}
int do_gensym( char *syntax, struct object *args )
{
char name[ 64 ];
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
snprintf( name, sizeof( name ), "<GENSYM#%d>", gensym_counter++ );
stack_push( stack, make_atom_from_symbol( name ));
return 0;
}
int do_libdir( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
stack_push( stack, make_atom_from_string( DATADIR, strlen( DATADIR )));
return 0;
}
int do_substring( char *syntax, struct object *args )
{
struct object *car1, *car2, *car3;
struct string *s;
char *ptr;
int arg2, arg3;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)3 );
if ( check_args( syntax, args ))
return 1;
car3 = stack_pop( stack );
car2 = stack_pop( stack );
car1 = stack_pop( stack );
arg2 = number( car2->data.atom );
arg3 = number( car3->data.atom );
if ( arg2 < 0 )
{
fprintf( stderr, "%s: index < 0.\n", syntax );
return 1;
}
if ( arg3 < 0 )
{
fprintf( stderr, "%s: length < 0.\n", syntax );
return 1;
}
if ( arg2 >= car1->data.atom->data.string->length )
{
fprintf( stderr, "%s: index beyond end of string argument.\n",
syntax );
return 1;
}
s = make_string();
ptr = &car1->data.atom->data.string->string[ arg2 ];
if ( arg3 == 0 || ( arg3 + arg2 ) > car1->data.atom->data.string->length )
arg3 = car1->data.atom->data.string->length - arg2;
string_append( s, '"' );
while( arg3-- )
string_append( s, *ptr++ );
stack_push( stack, make_atom_directly_from_string( s->str, s->used ));
free( s );
return 0;
}
int do_expand( char *syntax, struct object *args )
{
struct object *car1, *car2;
char *ptr;
int offset = 0, i, len, arg1;
struct string *s;
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
arg1 = number( car1->data.atom );
ptr = car2->data.atom->data.string->string;
len = car2->data.atom->data.string->length;
s = make_string();
for( i = 0; i < len; ++i )
{
if ( *ptr == '\t' )
{
int spaces;
spaces = arg1 - ( i + offset ) % arg1;
offset += spaces - 1;
while( spaces-- )
string_append( s, ' ' );
}
else
string_append( s, *ptr );
++ptr;
}
stack_push( stack, make_atom_from_string( s->str, s->used ));
string_free( s );
return 0;
}
int do_interact( char *syntax, struct object *args )
{
int i;
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( interactive )
{
fprintf( stderr, "%s: already running interactively.\n", syntax );
return 1;
}
interactive = 1;
i = stack->used;
stack_push( open_envs, local_env );
local_env = NULL;
for( ; ; )
{
int depth, result;
if ( mode == 0 )
canon( syntax );
fflush( stdout );
depth = parse( 0 );
if ( depth > 0 )
break;
else if ( depth < 0 )
fprintf( stderr, "%s: %d extra ')'\n", syntax, -depth );
result = evaluate();
close_descriptors();
if ( result == 0 )
{
if ( printer )
{
print_object( *( struct object **)stack->top );
putchar( '\n' );
}
}
stop = next_iteration = 0;
if ( thrown != NULL )
{
fprintf( stderr, "%s: uncaught \"throw\"\n", syntax );
thrown = NULL;
}
collect_garbage();
}
local_env = stack_pop( open_envs );
stack_truncate( stack, stack->used - i );
stack_push( stack, make_atom_from_number( 1 ));
interactive = 0;
return 0;
}
int do_current( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
stack_push( stack, make_atom_from_string( *arg_ptr, strlen( *arg_ptr )));
return 0;
}
int do_next( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( arg_ptr < last_arg )
{
++arg_ptr;
stack_push( stack, make_atom_from_string( *arg_ptr, strlen( *arg_ptr )));
}
else
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
int do_prev( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( arg_ptr > first_arg )
{
--arg_ptr;
stack_push( stack, make_atom_from_string( *arg_ptr, strlen( *arg_ptr )));
}
else
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
int do_rewind( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
arg_ptr = first_arg;
stack_push( stack, make_atom_from_string( *arg_ptr, strlen( *arg_ptr )));
return 0;
}
int do_pwd( char *syntax, struct object *args )
{
char d[ MAXPATHLEN + 1 ];
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
getcwd( d, sizeof( d ));
if ( d == NULL )
{
fprintf( stderr, "%s: getcwd(): %s.\n", syntax, strerror( errno ));
return 1;
}
stack_push( stack, make_atom_from_string( d, strlen( d )));
return 0;
}
int do_exit( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
exit( number( car->data.atom ));
return 0;
}
struct object *make_atom_from_table( struct hash_elt **table )
{
struct object *object;
struct atom *entry;
char buffer[ 64 ];
snprintf( buffer, sizeof( buffer ), "<TABLE#%d>", table_counter++ );
entry = get_id( buffer, strlen( buffer ), 1 );
entry->flags = ATOM_TABLE;
entry->data.hash = table;
object = make_object();
object->data.atom = entry;
return object;
}
int do_table( char *syntax, struct object *args )
{
struct hash_elt **table, **ptr;
int i;
stack_push( arg_stack, ( void *) 0 );
if ( check_args( syntax, args ))
return 1;
table = ( struct hash_elt **)memory( sizeof( struct hash_elt *) * HASH_SIZE );
ptr = table;
for( i = 0; i < HASH_SIZE; ++i )
*ptr++ = NULL;
stack_push( stack, make_atom_from_table( table ));
return 0;
}
struct object *make_atom_from_number_for_hash_key( int n )
{
struct object *obj;
char buffer[ 64 ];
snprintf( buffer, sizeof( buffer ), "%i", n );
obj = make_object();
obj->data.atom = get_id( buffer, strlen( buffer ), 1 );
obj->data.atom->flags = ATOM_FIXNUM ;
obj->data.atom->data.record = ( void *)n;
return obj;
}
int do_hash( char *syntax, struct object *args )
{
struct object *car1, *car2, *car3;
stack_push( arg_stack, ( void *)ERR_TABLE );
stack_push( arg_stack, ( void *)ERR_ATOM );
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)3 );
if ( check_args( syntax, args ))
return 1;
car3 = stack_pop( stack );
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( numberp( car2->flags ) )
{
struct object *obj;
obj = make_atom_from_number_for_hash_key( number( car2->data.atom ) );
insert_elt( car1->data.atom->data.hash, obj->data.atom->id, car3 );
}
else
insert_elt( car1->data.atom->data.hash, car2->data.atom->id, car3 );
stack_push( stack, car3 );
return 0;
}
int do_unhash( char *syntax, struct object *args )
{
struct object *car1, *car2;
stack_push( arg_stack, ( void *)ERR_TABLE );
stack_push( arg_stack, ( void *)ERR_ATOM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( numberp( car2->flags ) )
{
struct object *obj;
obj = make_atom_from_number_for_hash_key( number( car2->data.atom ) );
remove_elt( car1->data.atom->data.hash, obj->data.atom->id );
}
else
remove_elt( car1->data.atom->data.hash, car2->data.atom->id );
stack_push( stack, car2 );
return 0;
}
int do_lookup( char *syntax, struct object *args )
{
struct object *car1, *car2;
stack_push( arg_stack, ( void *)ERR_TABLE );
stack_push( arg_stack, ( void *)ERR_ATOM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( numberp( car2->flags ) )
{
struct object *obj;
obj = make_atom_from_number_for_hash_key( number( car2->data.atom ) );
car1 = lookup_elt( car1->data.atom->data.hash, obj->data.atom->id );
}
else
car1 = lookup_elt( car1->data.atom->data.hash, car2->data.atom->id );
if ( car1 == NULL )
{
stack_push( stack, make_object());
setlist( ( *( struct object **)stack->top )->flags );
}
else
stack_push( stack, car1 );
return 0;
}
int do_keys( char *syntax, struct object *args )
{
struct object *car, **ptr, *result;
struct stack *keys;
int idx;
stack_push( arg_stack, ( void *)ERR_TABLE );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
keys = get_hash_keys( car->data.atom->data.hash );
result = make_object();
setlist( result->flags );
stack_push( stack, result );
ptr = &result->data.head;
if ( keys->used == 0 )
result->data.head = NULL;
else
{
struct atom *entry;
for( idx = 0; idx < keys->used; ++idx )
{
*ptr = make_object();
entry = lookup_atom( ( int)keys->values[ idx ] );
if ( type( entry->flags ) == ATOM_FIXNUM )
{
setnumber( ( *ptr )->flags );
( *ptr )->data.atom = toptr( entry->data.record );
}
else
( *ptr )->data.atom = entry;
ptr = &( *ptr )->next;
}
}
stack_free( keys );
return 0;
}
int do_values( char *syntax, struct object *args )
{
struct object *car, **ptr, *result;
struct stack *values;
int idx;
stack_push( arg_stack, ( void *)ERR_TABLE );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
values = get_hash_values( car->data.atom->data.hash );
result = make_object();
setlist( result->flags );
stack_push( stack, result );
ptr = &result->data.head;
if ( values->used == 0 )
result->data.head = NULL;
else
{
for( idx = 0; idx < values->used; ++idx )
{
*ptr = duplicate_object( ( struct object *)values->values[ idx ] );
ptr = &( *ptr )->next;
}
}
stack_free( values );
return 0;
}
int do_redirect( char *syntax, struct object *args )
{
struct object *car1, *car2, *car3, *car4;
int flags, fd, arg1;
mode_t mode;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 1, -1 );
return 1;
}
if ( args->next == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 2, -1 );
return 1;
}
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
return 1;
}
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, -1 );
return 1;
}
if ( args->next->next != NULL )
{
stack_push( stack, args->next->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 3, -1 );
return 1;
}
if ( args->next->next->next != NULL )
{
stack_push( stack, args->next->next->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 4, -1 );
return 1;
}
car4 = stack_pop( stack );
if ( islist( car4->flags ) || numberp( car4->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 4, ERR_FIXNUM );
return 1;
}
if ( args->next->next->next->next != NULL )
{
print_err( ERR_MORE_ARGS, syntax, 4, -1 );
return 1;
}
}
else
car4 = NULL;
car3 = stack_pop( stack );
if ( islist( car3->flags ) || numberp( car3->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 3, ERR_FIXNUM );
return 1;
}
}
else
{
car3 = NULL;
car4 = NULL;
}
car2 = stack_pop( stack );
if ( islist( car2->flags ) ||
numberp( car2->flags ) ||
type( car2->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, 2, ERR_STRING );
return 1;
}
car1 = stack_pop( stack );
if ( islist( car1->flags ) || numberp( car1->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_FIXNUM );
return 1;
}
arg1 = number( car1->data.atom );
if ( arg1 < 0 || arg1 > 2 )
{
fprintf( stderr, "%s: descriptor %d out of range.\n", syntax, arg1 );
return 1;
}
flags = 0;
if ( arg1 )
{
fflush( ( arg1 == 1 ? stdout : stderr ));
flags = O_CREAT;
if ( car3 != NULL && number( car3->data.atom ))
flags = O_APPEND;
}
flags |= ( arg1 ? ( O_WRONLY | O_NONBLOCK ) :
( O_RDONLY | O_NONBLOCK ));
if ( car4 != NULL && number( car4->data.atom ))
flags |= ( arg1 ? O_EXLOCK : O_SHLOCK );
mode = getmode( setmode( "0600" ), 0 );
AGAIN:
if (( fd = open( car2->data.atom->data.string->string, flags, mode )) < 0 )
{
if ( errno == EINTR )
goto AGAIN;
switch( errno )
{
case ENOENT:
stack_push( stack, make_atom_from_number( -1 ));
break;
case EACCES:
stack_push( stack, make_atom_from_number( -2 ));
break;
case EBUSY:
case EAGAIN:
stack_push( stack, make_atom_from_number( -3 ));
break;
default:
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
}
return 0;
}
if ( arg1 && ( car3 == NULL || number( car3->data.atom ) == 0 ))
if ( ftruncate( fd, 0 ))
{
close( fd );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
if (( flags = dup( arg1 )) < 0 )
{
close( fd );
fprintf( stderr, "%s: dup: %s.\n", syntax, strerror( errno ));
return 1;
}
if ( arg1 )
fclose( (( arg1 == 1 ? stdout : stderr )));
stack_push( descriptors[ arg1 ], ( void *)flags );
if ( dup2( fd, arg1 ) < 0 )
{
close( fd );
stack_pop( descriptors[ arg1 ] );
fprintf( stderr, "%s: dup2: %s.\n", syntax, strerror( errno ));
return 1;
}
close( fd );
if ( arg1 )
{
FILE *file;
file = fdopen( arg1, ( car3 != NULL && number( car3->data.atom ) ? "a" : "w" ));
if ( file == NULL )
{
fprintf( stderr, "%s: fdopen: %s.\n", syntax, strerror( errno ));
return 1;
}
if ( arg1 == 1 )
stdout = file;
else
stderr = file;
}
else
getline_from_file( syntax, 1 );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
void resume( char *syntax, int arg1 )
{
int fd;
fd = ( int )stack_pop( descriptors[ arg1 ] );
if ( arg1 )
{
if ( arg1 == 1 && stdout != NULL )
fclose( stdout );
else if ( arg1 == 2 && stderr != NULL )
fclose( stderr );
}
if ( dup2( fd, arg1 ) < 0 )
{
fprintf( stderr, "%s: dup2: %s.\n", syntax, strerror( errno ));
close( fd );
return;
}
close( fd );
if ( arg1 == 0 )
getline_from_file( syntax, 2 );
else
{
if ( arg1 == 1 )
{
stdout = fdopen( arg1, "w" );
if ( stdout == NULL )
{
fprintf( stderr, "%s: fdopen: %s.\n", syntax, strerror( errno ));
return;
}
}
else
{
stderr = fdopen( arg1, "w" );
if ( stderr == NULL )
{
fprintf( stdout, "%s: fdopen: %s.\n", syntax, strerror( errno ));
return;
}
}
}
}
int do_resume( char *syntax, struct object *args )
{
int arg1;
struct object *car;
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
arg1 = number( car->data.atom );
if ( arg1 < 0 || arg1 > 2 )
{
fprintf( stderr, "%s: descriptor argument %d out of range.\n", syntax, arg1 );
return 1;
}
if ( descriptors[ arg1 ]->used == 0 )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
resume( syntax, arg1 );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_warn( char *syntax, struct object *args )
{
struct object *ptr;
int i;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
i = 1;
for( ptr = args; ptr != NULL; ptr = ptr->next )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, i, -1 );
return 1;
}
do_print_objects_strings_unquoted( stack_pop( stack ), 0, 2 );
++i;
}
fputc( '\n', stderr );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_getenv( char *syntax, struct object *args )
{
struct object *car;
char *p;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
p = getenv( car->data.atom->data.string->string );
if ( p == NULL )
stack_push( stack, make_atom_from_number( 0 ));
else
stack_push( stack, make_atom_from_string( p, strlen( p )));
return 0;
}
int do_directory( char *syntax, struct object *args )
{
struct object *car, **ptr, *result;
DIR *dir;
struct dirent *dp;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
if (( dir = opendir( car->data.atom->data.string->string )) == NULL )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
readdir( dir );
result = make_object();
setlist( result->flags );
stack_push( stack, result );
ptr = &result->data.head;
while(( dp = readdir( dir )) != NULL )
{
*ptr = make_atom_from_string( dp->d_name, dp->d_namlen );
ptr = &( *ptr )->next;
}
closedir( dir );
return 0;
}
int do_chomp( char *syntax, struct object *args )
{
struct object *car;
struct string *s;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
if ( car->data.atom->data.string->length )
{
int i;
s = make_string();
string_assign( s, car->data.atom->data.string->string,
car->data.atom->data.string->length );
i = s->used;
while( --i >= 0 )
{
if ( s->str[ i ] == '\r' || s->str[ i ] == '\n' )
string_erase( s, i );
else
break;
}
stack_push( stack, make_atom_from_string( s->str, s->used ));
string_free( s );
}
else
stack_push( stack, duplicate_object( car ));
return 0;
}
int do_chop( char *syntax, struct object *args )
{
char *new;
int len;
struct object *car;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
new = str_dup( car->data.atom->data.string->string,
car->data.atom->data.string->length );
len = car->data.atom->data.string->length;
if ( len )
{
new[ len - 1 ] = '\0';
stack_push( stack, make_atom_from_string( new, len - 1 ));
}
else
stack_push( stack, duplicate_object( car ));
free( new );
return 0;
}
int do_unlink( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
if ( unlink( car->data.atom->data.string->string ))
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_rmdir( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
if ( rmdir( car->data.atom->data.string->string ))
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_rename( char *syntax, struct object *args )
{
struct object *car1, *car2;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( rename( car1->data.atom->data.string->string,
car2->data.atom->data.string->string ) < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_words( char *syntax, struct object *args )
{
int i, last, result, flag, total;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if ( buffer->seq( buffer, &dbt_key, &dbt_value, R_LAST ) == -1 )
{
fprintf( stderr, "%s: db->seq: %s.\n", syntax, strerror( errno ));
stack_push( stack, make_atom_from_number( 0 ));
}
last = *( int *)dbt_key.data;
if ( !last )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
total = 0;
for( i = 1; i <= last; ++i )
{
char *ptr;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
key_data = i;
if (( result = buffer->get( buffer, &dbt_key, &dbt_value, 0 )) < 0 )
{
fprintf( stderr, "%s: db->get: %s.\n", syntax, strerror( errno ));
return 1;
}
else if ( result == 1 )
{
fprintf( stderr, "%s: db->get: key does not exist: %d.\n",
syntax, i );
return 1;
}
flag = 0;
ptr = ( char *)dbt_value.data;
while( *ptr )
{
if ( isspace( *ptr++ ))
{
if ( flag )
{
++total;
flag = 0;
}
continue;
}
flag = 1;
}
}
stack_push( stack, make_atom_from_number( total ));
return 0;
}
int do_time( char *syntax, struct object *args )
{
time_t t;
char buffer[ 32 ];
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( time( &t ) < 0 )
{
fprintf( stderr, "%s: time(): %s\n.", syntax, strerror( errno ));
return 1;
}
snprintf( buffer, sizeof( buffer ), "%ld", ( long int)t );
stack_push( stack, make_atom_from_string( buffer, -1 ));
return 0;
}
int do_random( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *obj;
float f;
int r;
obj = stack_pop( stack );
if ( number( obj->data.atom ) <= 0 )
{
fprintf( stderr, "%s: argument <= 0: %i\n", syntax,
number( obj->data.atom ));
return 1;
}
f = random();
r = number( obj->data.atom ) * f / RAND_MAX;
stack_push( stack, make_atom_from_number( r ));
}
return 0;
}
int do_date( char *syntax, struct object *args )
{
struct object *car1, *car2;
time_t t;
struct tm *lt;
int gmt = 0, really = 0, len;
char buffer[ 64 ];
if ( args != NULL )
{
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
return 1;
}
if ( args->next != NULL )
{
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, -1 );
return 1;
}
car2 = stack_pop( stack );
if ( args->next->next )
{
print_err( ERR_MORE_ARGS, syntax, 1, -1 );
return 1;
}
}
else
car2 = NULL;
car1 = stack_pop( stack );
if ( islist( car1->flags ) == 1 || numberp( car1->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_FIXNUM );
return 1;
}
if ( car2 != NULL )
{
if ( islist( car2->flags ) == 1 || numberp( car2->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 2, ERR_FIXNUM );
return 1;
}
really = number( car2->data.atom );
}
gmt = number( car1->data.atom );
}
if ( time( &t ) < 0 )
{
fprintf( stderr, "%s: time(): %s\n.", syntax, strerror( errno ));
return 1;
}
if ( gmt )
{
if (( lt = gmtime( &t )) == NULL )
{
fprintf( stderr, "%s: gmtime(): %s.\n", syntax, strerror( errno ));
return 1;
}
}
else
{
if (( lt = localtime( &t )) == NULL )
{
fprintf( stderr, "%s: localtime(): %s.\n", syntax, strerror( errno ));
return 1;
}
}
if ( strftime( buffer, sizeof( buffer ) - 1,
"%a, %d %b %Y %H:%M:%S %Z",
lt ) == 0 )
{
fprintf( stderr, "%s: strftime(): %s.\n", syntax, strerror( errno ));
return 1;
}
if ( gmt && really && ( len = strlen( buffer)) > 2 )
{
buffer[ --len ] = 'T';
buffer[ --len ] = 'M';
buffer[ --len ] = 'G';
}
stack_push( stack, make_atom_from_string( buffer, strlen( buffer )));
return 0;
}
int do_datethen( char *syntax, struct object *args )
{
struct object *car;
time_t t;
struct tm *lt;
int gmt = 0, i;
char buffer[ 64 ];
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 1, -1 );
return 1;
}
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
return 1;
}
if ( args->next != NULL )
{
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, -1 );
return 1;
}
car = stack_pop( stack );
if ( islist( car->flags ) == 1 || numberp( car->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 2, ERR_FIXNUM );
return 1;
}
if ( args->next->next != NULL )
{
print_err( ERR_MORE_ARGS, syntax, 1, -1 );
return 1;
}
gmt = number( car->data.atom );
}
car = stack_pop( stack );
if ( islist( car->flags ) == 1 || numberp( car->flags ))
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_STRING );
return 1;
}
if (( i = atoi( car->data.atom->data.string->string )) < 0 )
{
fprintf( stderr, "%s: negative time value supplied.\n", syntax );
return 1;
}
t = i;
if ( gmt )
{
if (( lt = gmtime( &t )) == NULL )
{
fprintf( stderr, "%s: gmtime(): %s.\n", syntax, strerror( errno ));
return 1;
}
}
else
{
if (( lt = localtime( &t )) == NULL )
{
fprintf( stderr, "%s: localtime(): %s.\n", syntax, strerror( errno ));
return 1;
}
}
if ( strftime( buffer, sizeof( buffer ) - 1,
"%a, %d %b %Y %H:%M:%S %Z",
lt ) == 0 )
{
fprintf( stderr, "%s: strftime(): %s.\n", syntax, strerror( errno ));
return 1;
}
stack_push( stack, make_atom_from_string( buffer, strlen( buffer )));
return 0;
}
int do_when( char *syntax, struct object *args )
{
struct object *cdr, *result;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
cdr = args->next;
if ( cdr == NULL )
{
fprintf( stderr, "%s: missing body expressions.\n", syntax );
return 1;
}
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: evaluation of test clause failed.\n",
syntax );
return 1;
}
result = *( struct object **)stack->top;
if ( !(( islist( result->flags ) == 1 && result->data.head == NULL ) ||
( islist( result->flags ) == 0 && ( result->data.atom == NULL ||
result->data.atom == empty->data.atom ))))
{
stack_pop( stack );
if ( do_progn( syntax, cdr ) )
{
if ( !stop )
fprintf( stderr, "%s: evaluation of subsequent expressions "
"failed.\n", syntax );
return 1;
}
}
return 0;
}
int do_unless( char *syntax, struct object *args )
{
struct object *cdr, *result;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
cdr = args->next;
if ( cdr == NULL )
{
fprintf( stderr, "%s: missing body expressions.\n", syntax );
return 1;
}
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: evaluation of test clause failed.\n",
syntax );
return 1;
}
result = *( struct object **)stack->top;
if (( islist( result->flags ) == 1 && result->data.head == NULL ) ||
( islist( result->flags ) == 0 && ( result->data.atom == NULL ||
result->data.atom == empty->data.atom )))
{
stack_pop( stack );
if ( do_progn( syntax, cdr ) )
{
if ( !stop )
fprintf( stderr, "%s: evaluation of subsequent expressions "
"failed.\n", syntax );
return 1;
}
}
return 0;
}
int do_test( char *syntax, struct object *args )
{
struct object *result;
if ( args == NULL || islist( args->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_LIST );
return 1;
}
stack_push( stack, args->data.head );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, 0 );
return 1;
}
result = stack_pop( stack );
if ( islist( result->flags ) ||
numberp( result->flags ) ||
type( result->data.atom->flags ) != ATOM_MACRO )
{
fprintf( stderr, "%s: function position did not evaluate"
" to a macro closure.\n", syntax );
return 1;
}
return apply_closure( syntax,
result->data.atom->data.closure,
args->data.head->next,
0 );
}
int do_continue( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
stop = 1;
next_iteration = 1;
thrown = NULL;
return 1;
}
int do_block( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
signal( SIGTTIN, SIG_IGN );
signal( SIGTTOU, SIG_IGN );
signal( SIGTSTP, SIG_IGN );
signal( SIGHUP, SIG_IGN );
signal( SIGTERM, SIG_IGN );
signal( SIGINT, SIG_IGN );
signal( SIGQUIT, SIG_IGN );
signal( SIGPIPE, SIG_IGN );
blocked = 1;
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_unblock( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
signal( SIGTTIN, SIG_DFL );
signal( SIGTTOU, SIG_DFL );
signal( SIGTSTP, SIG_DFL );
signal( SIGHUP, SIG_DFL );
signal( SIGTERM, SIG_DFL );
signal( SIGINT, SIG_DFL );
signal( SIGQUIT, SIG_DFL );
signal( SIGPIPE, SIG_DFL );
blocked = 0;
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_exists( char *syntax, struct object *args )
{
struct object *car;
struct stat stats;
int result;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
result = stat( car->data.atom->data.string->string, &stats );
if ( result < 0 )
{
if ( errno == ENOENT )
stack_push( stack, make_atom_from_number( 0 ));
else if ( errno == EACCES || errno == ENOTDIR )
stack_push( stack, make_atom_from_number( -1 ));
else
{
fprintf( stderr, "%s: %s.\n", syntax, strerror( errno ));
return 1;
}
}
else if ( S_ISREG( stats.st_mode ))
stack_push( stack, make_atom_from_number( 1 ));
else if ( S_ISDIR( stats.st_mode ))
stack_push( stack, make_atom_from_number( 2 ));
else if ( S_ISCHR( stats.st_mode ))
stack_push( stack, make_atom_from_number( 3 ));
else if ( S_ISBLK( stats.st_mode ))
stack_push( stack, make_atom_from_number( 4 ));
else if ( S_ISFIFO( stats.st_mode ))
stack_push( stack, make_atom_from_number( 5 ));
else if ( S_ISLNK( stats.st_mode ))
stack_push( stack, make_atom_from_number( 6 ));
else if ( S_ISSOCK( stats.st_mode ))
stack_push( stack, make_atom_from_number( 7 ));
else
stack_push( stack, make_atom_from_number( 8 ));
return 0;
}
int do_suspend( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
kill( 0, SIGSTOP );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_beep( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
beep();
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_length( char *syntax, struct object *args )
{
struct object *car, *item;
int i;
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
i = 0;
if ( islist( car->flags ))
{
for( item = car->data.head; item != NULL; item = item->next )
++i;
}
else if ( numberp( car->flags ) == 0 &&
type( car->data.atom->flags ) == ATOM_STRING )
i = car->data.atom->data.string->length;
else
{
fprintf( stderr, "%s: argument 1 did not evaluate to a string or"
" a list.\n", syntax );
return 1;
}
stack_push( stack, make_atom_from_number( i ));
return 0;
}
int do_strcmp( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
int i;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
i = strncmp( car1->data.atom->data.string->string,
car2->data.atom->data.string->string,
MIN( car1->data.atom->data.string->length,
car2->data.atom->data.string->length ) + 1 );
stack_push( stack, make_atom_from_number( i ));
}
return 0;
}
int do_fatal( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
fatal = 1;
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_nofatal( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
fatal = 0;
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
#ifdef SQL
int db_busy_handler( void *data, int tries )
{
struct timespec tv;
if ( tries == 1000 )
return 0;
tv.tv_sec = 0;
tv.tv_nsec = 250000;
nanosleep( &tv, NULL );
return 1;
}
int do_sqlp( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *arg1;
arg1 = stack_pop( stack );
if ( islist( arg1->flags ) ||
numberp( arg1->flags ) ||
type( arg1->data.atom->flags ) != ATOM_SQL )
stack_push( stack, make_atom_from_number( 0 ));
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_sqlite_open( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
sqlite3 *db;
const char *sql_err = NULL;
car = stack_pop( stack );
if( sqlite3_open( car->data.atom->data.string->string, &db ) != SQLITE_OK )
{
sql_err = sqlite3_errmsg( db );
stack_push( stack, make_atom_from_string( ( char *)sql_err, strlen( sql_err )));
sqlite3_close( db );
}
else
{
sqlite3_busy_handler( db, db_busy_handler, NULL );
stack_push( stack, make_atom_from_db( db ));
}
}
return 0;
}
int do_sqlite_close( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_DB );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
if ( car->data.atom->data.db == NULL )
stack_push( stack, make_atom_from_number( 0 ));
else
{
sqlite3_close( car->data.atom->data.db );
car->data.atom->data.db = NULL;
stack_push( stack, make_atom_from_number( 1 ));
}
}
return 0;
}
int sql_callback( void *data, int total, char **sql_vals, char **sql_cols )
{
char **ptr;
struct object **list_ptr;
int i;
if ( sql_list == *( struct object **)stack->top )
{
list_ptr = &sql_list->data.head;
*list_ptr = make_object();
sql_list = *list_ptr;
setlist( ( *list_ptr )->flags );
( *list_ptr )->next = NULL;
list_ptr = &( *list_ptr )->data.head;
ptr = sql_cols;
for( i = 0; i < total; ++i )
{
*list_ptr = make_atom_from_string( *ptr, strlen( *ptr ));
list_ptr = &( *list_ptr )->next;
*list_ptr = NULL;
++ptr;
}
}
list_ptr = &sql_list->next;
*list_ptr = make_object();
sql_list = *list_ptr;
setlist( ( *list_ptr )->flags );
( *list_ptr )->next = NULL;
list_ptr = &( *list_ptr )->data.head;
ptr = sql_vals;
for( i = 0; i < total; ++i )
{
*list_ptr = make_atom_from_string( *ptr, strlen( *ptr ));
list_ptr = &( *list_ptr )->next;
*list_ptr = NULL;
++ptr;
}
return 0;
}
int do_sqlite_exec( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_DB );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *sql, *db;
char *sql_err;
sql = stack_pop( stack );
db = stack_pop( stack );
if ( db->data.atom->data.db == NULL )
{
stack_push( stack, make_atom_from_string( "database has been closed", 24 ));
return 1;
}
sql_list = make_object();
setlist( sql_list->flags );
stack_push( stack, sql_list );
if ( sqlite3_exec( db->data.atom->data.db,
sql->data.atom->data.string->string,
sql_callback, NULL, &sql_err )
!= SQLITE_OK )
{
stack_pop( stack );
stack_push( stack, make_atom_from_string( sql_err, strlen( sql_err )));
free( sql_err );
}
}
return 0;
}
struct object *make_atom_from_prepared_sql( sqlite3_stmt *sql )
{
struct object *obj;
struct atom *entry;
char buffer[ 128 ];
snprintf( buffer, sizeof( buffer ), "<SQL#%d>", sql_counter++ );
entry = get_id( buffer, strlen( buffer ), 1 );
if ( entry->flags == 0 )
{
entry->flags = ATOM_SQL;
entry->data.sql = sql;
}
obj = make_object();
obj->data.atom = entry;
return obj;
}
int do_sqlite_prepare( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_DB );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
sqlite3_stmt *compiled;
const char *ignored;
struct object *arg1, *arg2;
arg2 = stack_pop( stack );
arg1 = stack_pop( stack );
if ( sqlite3_prepare( arg1->data.atom->data.db,
arg2->data.atom->data.string->string,
arg2->data.atom->data.string->length,
&compiled,
&ignored ) != SQLITE_OK )
stack_push( stack,
make_atom_from_string(
( char *)sqlite3_errmsg( arg1->data.atom->data.db ), -1 ));
else
stack_push( stack, make_atom_from_prepared_sql( compiled ));
}
return 0;
}
int do_sqlite_bind( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_SQL );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)3 );
if ( check_args( syntax, args ))
return 1;
{
struct object *arg1, *arg2, *arg3;
arg3 = stack_pop( stack );
arg2 = stack_pop( stack );
arg1 = stack_pop( stack );
if ( arg1->data.atom->data.sql == NULL )
{
fprintf( stderr, "%s: compiled SQL statement has been finalized.\n",
syntax );
return 1;
}
if ( sqlite3_bind_text( arg1->data.atom->data.sql,
number( arg2->data.atom ),
arg3->data.atom->data.string->string,
arg3->data.atom->data.string->length,
SQLITE_TRANSIENT ) != SQLITE_OK )
stack_push( stack,
make_atom_from_string(
( char *)sqlite3_errmsg( sqlite3_db_handle( arg1->data.atom->data.sql )),
-1 ));
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_sqlite_step( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_SQL );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *arg;
int code;
arg = stack_pop( stack );
if ( arg->data.atom->data.sql == NULL )
{
fprintf( stderr, "%s: compiled SQL statement has been finalized.\n",
syntax );
return 1;
}
if (( code = sqlite3_step( arg->data.atom->data.sql )) != SQLITE_ROW )
{
if ( code == SQLITE_DONE )
stack_push( stack, make_atom_from_number( 0 ));
else
stack_push( stack,
make_atom_from_string(
( char *)sqlite3_errmsg( sqlite3_db_handle( arg->data.atom->data.sql )), -1 ));
}
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_sqlite_row( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_SQL );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *arg1, *result, **ptr;
int total, i, len;
const char *column;
arg1 = stack_pop( stack );
if ( arg1->data.atom->data.sql == NULL )
{
fprintf( stderr, "%s: compiled SQL statement has been finalized.\n",
syntax );
return 1;
}
total = sqlite3_column_count( arg1->data.atom->data.sql );
result = make_object();
setlist( result->flags );
stack_push( stack, result );
for( i = 0, ptr = &result->data.head; i < total; ++i, ptr = &( *ptr )->next )
{
len = sqlite3_column_bytes( arg1->data.atom->data.sql, i );
if (( column = sqlite3_column_text( arg1->data.atom->data.sql, i )) == NULL )
{
stack_push( stack,
make_atom_from_string(
( char *)sqlite3_errmsg( sqlite3_db_handle( arg1->data.atom->data.sql )), -1 ));
return 1;
}
*ptr = make_atom_from_string( ( char *)column, len );
}
}
return 0;
}
int do_sqlite_finalize( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_SQL );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *arg1;
arg1 = stack_pop( stack );
if ( arg1->data.atom->data.sql == NULL )
{
fprintf( stderr, "%s: compiled SQL statement has already been finalized.\n",
syntax );
return 1;
}
if ( sqlite3_finalize( arg1->data.atom->data.sql ) != SQLITE_OK )
stack_push( stack,
make_atom_from_string(
( char *)sqlite3_errmsg( sqlite3_db_handle( arg1->data.atom->data.sql )), -1 ));
else
{
stack_push( stack, make_atom_from_number( 1 ));
arg1->data.atom->data.sql = NULL;
}
}
return 0;
}
int do_sqlite_reset( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_SQL );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *arg1;
arg1 = stack_pop( stack );
if ( arg1->data.atom->data.sql == NULL )
{
fprintf( stderr, "%s: compiled SQL statement has been finalized.\n",
syntax );
return 1;
}
if ( sqlite3_reset( arg1->data.atom->data.sql ) != SQLITE_OK )
stack_push( stack,
make_atom_from_string(
( char *)sqlite3_errmsg( sqlite3_db_handle( arg1->data.atom->data.sql )), -1 ));
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
#endif
int do_stack( char *syntax, struct object *args )
{
struct object *result;
struct stack *stk;
int i;
i = 0;
if ( args != NULL )
{
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
return 1;
}
result = stack_pop( stack );
if ( islist( result->flags ) ||
numberp( result->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_FIXNUM );
return 1;
}
i = number( result->data.atom );
result = NULL;
if ( i < 0 )
{
fprintf( stderr, "%s: initialize size < 0: %d.\n", syntax, i );
return 1;
}
}
stk = make_stack();
stack_push( stack, make_atom_from_stack( stk ));
while( i-- )
{
struct object *obj;
obj = make_object();
setlist( obj->flags );
stack_push( stk, obj );
}
return 0;
}
int do_pop( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STACK );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *obj;
struct stack *stk;
obj = stack_pop( stack );
stk = obj->data.atom->data.stack;
obj = stack_pop( stk );
if ( obj == NULL )
{
obj = make_object();
setlist( obj->flags );
}
stack_push( stack, obj );
}
return 0;
}
int do_push( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STACK );
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
stack_push( car1->data.atom->data.stack, car2 );
stack_push( stack, car2 );
}
return 0;
}
int do_unshift( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STACK );
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
int i;
struct object *car1, *car2;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( car1->data.atom->data.stack->used )
{
stack_push( car1->data.atom->data.stack, NULL );
for( i = car1->data.atom->data.stack->used - 1; i; --i )
car1->data.atom->data.stack->values[ i ] =
car1->data.atom->data.stack->values[ i - 1 ];
car1->data.atom->data.stack->values[ 0 ] = car2;
}
else
stack_push( car1->data.atom->data.stack, car2 );
stack_push( stack, car2 );
}
return 0;
}
int do_shift( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STACK );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
int i;
struct object *car, *result;
car = stack_pop( stack );
if ( car->data.atom->data.stack->used == 0 )
{
result = make_object();
setlist( result->flags );
}
else
{
result = car->data.atom->data.stack->values[ 0 ];
for( i = 0; i < car->data.atom->data.stack->used - 1; ++i )
car->data.atom->data.stack->values[ i ] =
car->data.atom->data.stack->values[ i + 1 ];
stack_pop( car->data.atom->data.stack );
}
stack_push( stack, result );
}
return 0;
}
int do_used( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STACK );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
struct stack *stk;
car = stack_pop( stack );
stk = car->data.atom->data.stack;
stack_push( stack, make_atom_from_number( stk->used ));
}
return 0;
}
int do_index( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STACK );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
struct stack *stk;
int i;
car2 = stack_pop( stack );
i = number( car2->data.atom );
car1 = stack_pop( stack );
stk = car1->data.atom->data.stack;
if ( i < 0 )
{
fprintf( stderr, "%s: index < 0: %d.\n", syntax, i );
return 1;
}
else if ( i >= stk->used )
{
fprintf( stderr, "%s: index %d out of range.\n", syntax, i );
return 1;
}
stack_push( stack, stk->values[ i ] );
}
return 0;
}
int do_store( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STACK );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)3 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2, *car3;
struct stack *stk;
int i;
car3 = stack_pop( stack );
car2 = stack_pop( stack );
i = number( car2->data.atom );
car1 = stack_pop( stack );
stk = car1->data.atom->data.stack;
if ( i < 0 || i >= stk->used )
{
fprintf( stderr, "%s: index %d out of range.\n", syntax, i );
return 1;
}
stack_push( stack, stk->values[ i ] = car3 );
}
return 0;
}
int do_topidx( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STACK );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
struct stack *stk;
car = stack_pop( stack );
stk = car->data.atom->data.stack;
stack_push( stack, make_atom_from_number( stk->used - 1 ));
}
return 0;
}
int do_extract( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_CLOSURE );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *obj, *result;
char t;
obj = stack_pop( stack );
t = type( obj->data.atom->flags );
result = make_object();
setlist( result->flags );
stack_push( stack, result );
result->data.head = make_object();
if ( t == ATOM_CLOSURE )
result->data.head->data.atom = get_id( "lambda", 6, 1 );
else
result->data.head->data.atom = get_id( "macro", 5, 1 );
result->data.head->next = obj->data.atom->data.closure->text;
}
return 0;
}
int do_let( char *syntax, struct object *args )
{
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, 0 );
return 1;
}
if ( islist( args->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_LIST );
return 1;
}
if ( args->data.head == NULL )
{
fprintf( stderr, "%s: argument 1 is the empty list.\n",
syntax );
return 1;
}
if ( args->next == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 2, 0 );
return 1;
}
{
struct closure *closure;
struct object *ptr, *sym_list, *arg_list, **ptr2;
int i;
sym_list = make_object();
setlist( sym_list->flags );
ptr2 = &sym_list->data.head;
for( i = 1, ptr = args->data.head; ptr!= NULL; ++i, ptr = ptr->next )
{
if ( islist( ptr->flags ) == 0 )
{
fprintf( stderr, "%s: element %d of argument 1 is not a list.\n",
syntax, i );
return 1;
}
if ( ptr->data.head == NULL )
{
fprintf( stderr, "%s: element %d of argument 1 is the empty list.\n",
syntax, i );
return 1;
}
if ( ptr->data.head->next == NULL )
{
fprintf( stderr, "%s: element %d of argument 1 has only one "
"sub-element.\n", syntax, i );
return 1;
}
if ( ptr->data.head->next->next != NULL )
{
fprintf( stderr, "%s: element %d of argument 1 has more "
"than two sub-elements.\n", syntax, i );
return 1;
}
if ( islist( ptr->data.head->flags ) == 1 ||
numberp( ptr->data.head->flags ) ||
type( ptr->data.head->data.atom->flags ) != ATOM_SYMBOL )
{
fprintf( stderr, "%s: first sub-element of element %d of argument 1"
" is not a symbol.\n", syntax, i );
return 1;
}
*ptr2 = make_object();
( *ptr2 )->data.atom = ptr->data.head->data.atom;
ptr2 = &( *ptr2 )->next;
}
*ptr2 = NULL;
arg_list = make_object();
setlist( arg_list->flags );
ptr2 = &arg_list->data.head;
for( ptr = args->data.head; ptr != NULL; ptr = ptr->next )
{
*ptr2 = make_object();
**ptr2 = *ptr->data.head->next;
ptr2 = &( *ptr2 )->next;
}
*ptr2 = NULL;
sym_list->next = args->next;
closure = ( struct closure *)memory( sizeof( struct closure ));
closure->text = sym_list;
closure->env = local_env;
stack_push( stack, arg_list );
stack_push( stack, make_atom_from_closure( closure, 0 ));
i = apply_closure( syntax, closure, arg_list->data.head, 1 );
if ( i == 0 )
{
ptr = stack_pop( stack );
stack_pop( stack );
stack_pop( stack );
stack_push( stack, ptr );
}
return i;
}
}
int do_letn( char *syntax, struct object *args )
{
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, 0 );
return 1;
}
if ( islist( args->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_LIST );
return 1;
}
if ( args->data.head == NULL )
{
fprintf( stderr, "%s: argument 1 is the empty list.\n",
syntax );
return 1;
}
if ( args->next == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 2, 0 );
return 1;
}
{
struct object *result, *ptr, **ptr2, **ptr3;
int i;
result = NULL;
ptr2 = &result;
for( i = 1, ptr = args->data.head; ptr!= NULL; ++i, ptr = ptr->next )
{
if ( islist( ptr->flags ) == 0 )
{
fprintf( stderr, "%s: element %d of argument 1 is not a list.\n",
syntax, i );
return 1;
}
if ( ptr->data.head == NULL )
{
fprintf( stderr, "%s: element %d of argument 1 is the empty list.\n",
syntax, i );
return 1;
}
if ( ptr->data.head->next == NULL )
{
fprintf( stderr, "%s: element %d of argument 1 has only one "
"sub-element.\n", syntax, i );
return 1;
}
if ( ptr->data.head->next->next != NULL )
{
fprintf( stderr, "%s: element %d of argument 1 has more "
"than two sub-elements.\n", syntax, i );
return 1;
}
if ( numberp( ptr->data.head->flags ) ||
type( ptr->data.head->data.atom->flags ) != ATOM_SYMBOL )
{
fprintf( stderr, "%s: first sub-element of element %d of argument 1"
" is not a symbol.\n", syntax, i );
return 1;
}
*ptr2 = make_object();
setlist( ( *ptr2 )->flags );
ptr2 = &( *ptr2 )->data.head;
*ptr2 = make_object();
( *ptr2 )->data.atom = get_id( "let", 3, 1 );
ptr2 = &( *ptr2 )->next;
*ptr2 = make_object();
setlist( ( *ptr2 )->flags );
ptr3 = &( *ptr2 )->next;
ptr2 = &( *ptr2 )->data.head;
*ptr2 = make_object();
setlist( ( *ptr2 )->flags );
( *ptr2 )->next = NULL;
ptr2 = &( *ptr2 )->data.head;
*ptr2 = ptr->data.head;
ptr2 = ptr3;
}
*ptr2 = args->next;
stack_push( stack, result );
}
return evaluate();
}
int do_labels( char *syntax, struct object *args )
{
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, 0 );
return 1;
}
if ( islist( args->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_LIST );
return 1;
}
if ( args->data.head == NULL )
{
fprintf( stderr, "%s: argument 1 is the empty list.\n",
syntax );
return 1;
}
if ( args->next == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 2, 0 );
return 1;
}
{
struct object *ptr, *ptr3, *sym_list, *func_list, **ptr2, *result;
int i;
sym_list = make_object();
setlist( sym_list->flags );
ptr2 = &sym_list->data.head;
for( i = 1, ptr = args->data.head; ptr!= NULL; ++i, ptr = ptr->next )
{
if ( islist( ptr->flags ) == 0 )
{
fprintf( stderr, "%s: element %d of argument 1 is not a list.\n",
syntax, i );
return 1;
}
if ( ptr->data.head == NULL )
{
fprintf( stderr, "%s: element %d of argument 1 is the empty list.\n",
syntax, i );
return 1;
}
if ( ptr->data.head->next == NULL )
{
fprintf( stderr, "%s: element %d of argument 1 has only one "
"sub-element.\n", syntax, i );
return 1;
}
if ( ptr->data.head->next->next != NULL )
{
fprintf( stderr, "%s: element %d of argument 1 has more "
"than two sub-elements.\n", syntax, i );
return 1;
}
if ( numberp( ptr->data.head->flags ) ||
type( ptr->data.head->data.atom->flags ) != ATOM_SYMBOL )
{
fprintf( stderr, "%s: first sub-element of element %d of argument 1"
" is not a symbol.\n", syntax, i );
return 1;
}
*ptr2 = make_object();
( *ptr2 )->data.atom = ptr->data.head->data.atom;
ptr2 = &( *ptr2 )->next;
}
*ptr2 = NULL;
func_list = make_object();
setlist( func_list->flags );
ptr2 = &func_list->data.head;
ptr3 = sym_list->data.head;
for( i = 1, ptr = args->data.head; ptr != NULL; ptr = ptr->next, ++i )
{
if ( islist( ptr->data.head->next->flags ) == 0 ||
ptr->data.head->next->data.head == NULL ||
islist( ptr->data.head->next->data.head->flags ) == 1 ||
( ptr->data.head->next->data.head->data.atom->id != lambda_id &&
ptr->data.head->next->data.head->data.atom->id != macro_id ))
{
fprintf( stderr, "%s: second sub-element of element %d of"
" argument 1 is not a lambda or macro expression.\n",
syntax, i );
return 1;
}
*ptr2 = make_object();
setlist( ( *ptr2 )->flags );
( *ptr2 )->data.head = make_atom_from_symbol( "set" );
( *ptr2 )->data.head->next = make_object();
setlist( ( *ptr2 )->data.head->next->flags );
( *ptr2 )->data.head->next->data.head =
make_atom_from_symbol( "quote" );
( *ptr2 )->data.head->next->data.head->next =
make_atom_from_symbol( ptr3->data.atom->syntax );
( *ptr2 )->data.head->next->next = ptr->data.head->next;
ptr2 = &( *ptr2 )->next;
ptr3 = ptr3->next;
}
*ptr2 = args->next;
result = make_object();
setlist( result->flags );
stack_push( stack, result );
result->data.head = make_object();
setlist( result->data.head->flags );
result->data.head->data.head = make_atom_from_symbol( "lambda" );
result->data.head->data.head->next = sym_list;
sym_list->next = func_list->data.head;
ptr2 = &result->data.head->next;
for( ptr = args->data.head; ptr != NULL; ptr = ptr->next )
{
*ptr2 = make_object();
setlist( ( *ptr2 )->flags );
ptr2 = &( *ptr2 )->next;
}
}
return evaluate();
}
int do_cond( char *syntax, struct object *args )
{
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, 0 );
return 1;
}
{
struct object *ptr, *result = NULL;
int i;
for( i = 1, ptr = args; ptr != NULL; ptr = ptr->next, ++i )
{
if ( islist( ptr->flags ) == 0 )
{
fprintf( stderr, "%s: argument %d is not a list.\n", syntax, i );
return 1;
}
if ( ptr->data.head == NULL )
{
fprintf( stderr, "%s: argument %d is the empty list.\n",
syntax, i );
return 1;
}
if ( ptr->data.head->next == NULL )
{
fprintf( stderr, "%s: argument %d has only one element.\n",
syntax, i );
return 1;
}
stack_push( stack, ptr->data.head );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, i, 0 );
return 1;
}
result = stack_pop( stack );
if (( islist( result->flags ) == 1 && result->data.head == NULL ) ||
result->data.atom == NULL ||
result->data.atom == empty->data.atom )
continue;
if ( do_progn( syntax, ptr->data.head->next ))
{
if ( !stop )
fprintf( stderr, "%s: error evaluating body expression %d.\n",
syntax, i );
return 1;
}
else
return 0;
}
stack_push( stack, result );
}
return 0;
}
int do_transfer( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)5 );
if ( check_args( syntax, args ))
return 1;
if ( buffer_stack->used == 0 )
{
fprintf( stderr, "%s: no buffers have been opened.\n", syntax );
return 1;
}
{
struct object *obj;
int bn[ 2 ], f1, t1, t2, j, i, inc;
DB *bp[ 2 ];
obj = stack_pop( stack );
t2 = number( obj->data.atom );
obj = stack_pop( stack );
bn[ 1 ] = number( obj->data.atom );
obj = stack_pop( stack );
t1 = number( obj->data.atom );
obj = stack_pop( stack );
f1 = number( obj->data.atom );
obj = stack_pop( stack );
bn[ 0 ] = number( obj->data.atom );
for( j = 0; j < 2; ++j )
{
for( i = 0; i < buffer_stack->used; ++i )
{
if ( buffer_stack->values[ i ] != NULL )
{
if ( i == bn[ j ] )
goto CONT;
}
}
fprintf( stderr, "%s: buffer %d is not open.\n", syntax, bn[ j ] );
return 1;
CONT:
bp[ j ] = buffer_stack->values[ i ];
}
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if (( i = buffer->seq( bp[ 0 ], &dbt_key, &dbt_value, R_LAST )) == -1 )
{
fprintf( stderr, "%s: db->seq: %s.\n", syntax, strerror( errno ));
return 1;
}
else if ( i == 1 )
{
fprintf( stderr, "%s: buffer %d is empty.\n", syntax, bn[ 0 ] );
return 1;
}
if ( f1 < 1 || f1 > *( int *)dbt_key.data )
{
fprintf( stderr, "%s: argument 2 out of range: %d.\n", syntax, f1 );
return 1;
}
if ( t1 < 1 || t1 > *( int *)dbt_key.data )
{
fprintf( stderr, "%s: argument 3 out of range: %d.\n", syntax, t1 );
return 1;
}
if (( i = buffer->seq( bp[ 1 ], &dbt_key, &dbt_value, R_LAST )) == -1 )
{
fprintf( stderr, "%s: db->seq: %s.\n", syntax, strerror( errno ));
return 1;
}
else if ( i == 1 && t2 != 0 )
{
fprintf( stderr, "%s: buffer %d is empty.\n", syntax, bn[ 1 ] );
return 1;
}
if ( t2 < 0 || t2 > *( int *)dbt_key.data )
{
fprintf( stderr, "%s: argument 5 out of range: %d.\n", syntax, f1 );
return 1;
}
inc = ( f1 < t1 ? 1 : -1 );
for( i = f1; ; i += inc )
{
key_data = i;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if ( buffer->get( bp[ 0 ], &dbt_key, &dbt_value, 0 ))
{
fprintf( stderr, "%s: db->get: %s.\n", syntax, strerror( errno ));
return 1;
}
key_data = t2;
if ( buffer->put( bp[ 1 ], &dbt_key, &dbt_value, R_IAFTER ))
{
fprintf( stderr, "%s: db->put: %s.\n", syntax, strerror( errno ));
return 1;
}
if ( i == t1 )
break;
++t2;
}
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int pipe_open( char *syntax, char *task, int wrt, int std, int *rpid )
{
int fd[ 2 ], pid, flag;
char *args[ 4 ];
if ( pipe( &fd[ 0 ] ) < 0 )
{
fprintf( stderr, "%s: pipe: %s.\n", syntax, strerror( errno ));
return -1;
}
switch(( pid = fork() ))
{
case -1:
close( fd[ 0 ] );
close( fd[ 1 ] );
fprintf( stderr, "%s: fork: %s.\n", syntax, strerror( errno ));
return -1;
case 0:
if (( dup2( fd[ 1 ], !wrt )) < 0 )
{
fprintf( stderr, "%s (child): dup2: %s.\n", syntax, strerror( errno ));
_exit( 1 );
}
close( fd[ 0 ] );
close( fd[ 1 ] );
args[ 0 ] = "/bin/sh";
args[ 1 ] = "-c";
args[ 2 ] = task;
args[ 3 ] = NULL;
execv( args[ 0 ], args );
_exit( 1 );
default:
close( fd[ 1 ] );
if ( std )
{
if (( flag = dup( wrt )) < 0 )
{
close( fd[ 0 ] );
fprintf( stderr, "%s: dup: %s.\n", syntax, strerror( errno ));
return -1;
}
stack_push( descriptors[ wrt ], ( void *)flag );
if ( wrt )
fclose(( wrt == 1 ? stdout : stderr ));
if ( dup2( fd[ 0 ], wrt ) < 0 )
{
close( fd[ 0 ] );
close( ( int )stack_pop( descriptors[ wrt ] ));
fprintf( stderr, "%s: dup2: %s.\n", syntax, strerror( errno ));
return -1;
}
close( fd[ 0 ] );
if ( wrt == 1 )
{
stdout = fdopen( wrt, "w" );
if ( stdout == NULL )
{
fprintf( stderr, "%s: fdopen: %s.\n", syntax, strerror( errno ));
return -1;
}
}
else if ( wrt == 2 )
{
stderr = fdopen( wrt, "w" );
if ( stderr == NULL )
{
fprintf( stdout, "%s: fdopen: %s.\n", syntax, strerror( errno ));
return -1;
}
}
}
}
if ( rpid != NULL )
*rpid = pid;
return ( std ? pid : fd[ 0 ] );
}
int do_pipe( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
int arg1, pid;
struct object *car1, *car2;
car1 = stack_pop( stack );
car2 = stack_pop( stack );
arg1 = number( car2->data.atom );
if ( arg1 < 0 || arg1 > 2 )
{
fprintf( stderr, "%s: argument 1 out of range: %d.\n", syntax, arg1 );
return 1;
}
pid = pipe_open( syntax, car1->data.atom->data.string->string, arg1, 1, NULL );
if ( pid == -1 )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
if ( arg1 == 0 )
getline_from_file( syntax, 1 );
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_unsetenv( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
unsetenv( car->data.atom->data.string->string );
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_setenv( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( *car1->data.atom->data.string->string == '\0' )
{
fprintf( stderr, "%s: argument 1 is empty string.\n", syntax );
return 1;
}
/*
* I believe unsetting the variable first avoids the memory leak
* described in setenv(3). Am I right?
*/
unsetenv( car1->data.atom->data.string->string );
if ( setenv( car1->data.atom->data.string->string,
car2->data.atom->data.string->string, 1 ))
{
fprintf( stderr, "%s: setenv: %s.\n", syntax, strerror( errno ));
return 1;
}
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int child_open( char *syntax, char *child )
{
int fd[ 2 ], pid;
char *args[ 4 ];
if ( socketpair( PF_UNIX, SOCK_STREAM, 0, &fd[ 0 ] ) < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return -1;
}
switch(( pid = fork() ))
{
case -1:
close( fd[ 0 ] );
close( fd[ 1 ] );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return -1;
case 0:
if ( dup2( fd[ 1 ], 0 ) < 0 ||
dup2( fd[ 1 ], 1 ) < 0 ||
dup2( fd[ 1 ], 2 ) < 0 )
{
fprintf( stderr, "%s (child): dup2: %s.\n", syntax, strerror( errno ));
_exit( 1 );
}
close( fd[ 0 ] );
close( fd[ 1 ] );
args[ 0 ] = "/bin/sh";
args[ 1 ] = "-c";
args[ 2 ] = child;
args[ 3 ] = NULL;
execvp( args[ 0 ], args );
_exit( 1 );
default:
close( fd[ 1 ] );
child_pid = pid;
}
stack_push( stack, make_atom_from_number( 1 ));
return fd[ 0 ];
}
int open_remote( char *name, int port )
{
int fd;
struct sockaddr_in serv_addr;
struct hostent *host;
fd = socket( PF_INET, SOCK_STREAM, 0 );
if ( fd == -1 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return -1;
}
bzero( &serv_addr, sizeof( serv_addr ));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons( port );
host = gethostbyname( name );
if ( host == NULL )
{
stack_push( stack, make_atom_from_string( ( char *)hstrerror( h_errno ), -1 ));
return -1;
}
memcpy( &serv_addr.sin_addr, *host->h_addr_list, sizeof( struct in_addr ));
if ( connect( fd, ( struct sockaddr *)&serv_addr, sizeof( serv_addr )) == -1 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return -1;
}
child_pid = -2;
stack_push( stack, make_atom_from_number( 1 ));
return fd;
}
int do_child_open( char *syntax, struct object *args )
{
int remote;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
remote = 0;
if ( args->next != NULL )
{
if ( args->next->next != NULL )
{
print_err( ERR_MORE_ARGS, syntax, 2, -1 );
return 1;
}
remote = 1;
}
if ( child_pid != -1 )
{
fprintf( stderr, "%s: an inferior process is already running.\n", syntax );
return 1;
}
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, 0 );
return 1;
}
if ( remote )
{
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, 0 );
return 1;
}
}
{
struct object *name, *port = NULL;
if ( remote )
{
port = stack_pop( stack );
if ( islist( port->flags ) || numberp( port->flags ) == 0 )
{
fprintf( stderr, "%s: port number argument is not a fixnum.\n", syntax );
return 1;
}
}
name = stack_pop( stack );
if ( islist( name->flags ) || numberp( name->flags ) ||
type( name->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_STRING );
return 1;
}
if ( remote )
child_fd = open_remote( name->data.atom->data.string->string, number( port->data.atom ));
else
child_fd = child_open( syntax, name->data.atom->data.string->string );
}
child_eof = 0;
return 0;
}
int do_child_running( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
stack_push( stack, make_atom_from_number( ( child_pid == -1 ? 0 : 1 )));
return 0;
}
int do_child_write( char *syntax, struct object *args )
{
int i;
struct object *car, *result;
if ( child_pid == -1 )
{
fprintf( stderr, "%s: an inferior process is not running.\n", syntax );
return 1;
}
else if ( child_eof )
{
fprintf( stderr, "%s: the writable half of the connection has been closed.\n", syntax );
return 1;
}
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
for( i = 1, car = args; car != NULL; car = car->next, ++i )
{
stack_push( stack, car );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, i, -1 );
return 1;
}
result = *( struct object **)stack->top;
if ( islist( result->flags ) ||
numberp( result->flags ) ||
type( result->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, i, ERR_STRING );
return 1;
}
}
{
char *ptr, *current;
int j, len, written;
j = i - 1;
while( --i )
{
ptr = (( struct object *)stack->values[ stack->used - i ] )->data.atom->data.string->string;
len = (( struct object *)stack->values[ stack->used - i ] )->data.atom->data.string->length;
current = ptr;
written = 0;
do
{
current += written;
len -= written;
if (( written = write( child_fd, current, len )) < 0 )
{
fprintf( stderr, "%s: write: %s.\n", syntax, strerror( errno ));
return 1;
}
}
while( written < len );
}
stack_truncate( stack, j );
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_child_close( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( child_fd != -1 )
{
if ( child_eof )
{
if ( shutdown( child_fd, SHUT_RD ) < 0 )
{
fprintf( stderr, "%s: shutdown(): %s.\n", syntax, strerror( errno ));
return 1;
}
child_eof = 0;
}
else
close( child_fd );
child_fd = -1;
}
if ( child_pid == -2 )
child_pid = -1;
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int check_child( int block, char *syntax )
{
int result;
int fd;
fd_set in_set;
struct timeval timeval, *timeptr;
if ( block )
timeptr = NULL;
else
{
timeval.tv_sec = 0;
timeval.tv_usec = 0;
timeptr = &timeval;
}
fd = child_fd;
FD_ZERO( &in_set );
FD_SET( fd, &in_set );
if(( result = select( fd + 1, &in_set, NULL, NULL, timeptr )) < 0 )
if ( errno != EINTR )
{
fprintf( stderr, "%s: select: %s.\n", syntax, strerror( errno ));
return 1;
}
if ( result && FD_ISSET( fd, &in_set ))
stack_push( stack, make_atom_from_number( 1 ));
else
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
int do_child_ready( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( child_fd == -1 )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
return check_child( 0, syntax );
}
int do_child_wait( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( child_fd == -1 )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
return check_child( 1, syntax );
}
int do_child_read( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( child_fd == -1 )
{
fprintf( stderr, "%s: an inferior process is not running.\n", syntax );
return 1;
}
{
int result;
int fd;
fd_set in_set;
char buffer[ 1024 ];
struct timeval timeval;
timeval.tv_sec = 30;
timeval.tv_usec = 0;
fd = child_fd;
FD_ZERO( &in_set );
FD_SET( fd, &in_set );
if (( result = select( fd + 1, &in_set, NULL, NULL, &timeval )) < 0 )
if ( errno != EINTR )
{
fprintf( stderr, "%s: select: %s.\n", syntax, strerror( errno ));
return 1;
}
if ( result && FD_ISSET( fd, &in_set ))
{
if (( result = read( fd, buffer, sizeof( buffer ) - 1 )) < 0 )
{
fprintf( stderr, "%s: read: %s.\n", syntax, strerror( errno ));
return 1;
}
if ( result == 0 )
{
do_child_close( syntax, NULL );
stack_pop( stack );
stack_push( stack, make_atom_from_number( 0 ));
}
else
{
buffer[ result ] = '\0';
stack_push( stack, make_atom_from_string( buffer, result ));
}
}
else
stack_push( stack, make_atom_from_string( "", 0 ));
}
return 0;
}
int do_protect( char *syntax, struct object *args )
{
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
{
struct object *temp, *temp_thrown;
int temp_stop;
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, -1 );
temp_thrown = thrown;
temp_stop = stop;
temp = NULL;
}
else
{
temp_thrown = NULL;
temp_stop = 0;
temp = stack_pop( stack );
}
if ( args->next != NULL && do_progn( syntax, args->next ))
return 1;
stop = temp_stop;
thrown = temp_thrown;
if ( temp == NULL )
return 1;
stack_pop( stack );
stack_push( stack, temp );
}
return 0;
}
int do_tailcall( char *syntax, struct object *args )
{
struct stack *temp;
struct object *car;
struct closure *closure;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
if ( current_closure == NULL )
{
fprintf( stderr, "%s: no closure is being applied.\n", syntax );
return 1;
}
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 0, 1 );
return 1;
}
car = stack_pop( stack );
if ( numberp( car->flags ) )
{
if ( car->data.atom != NULL )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_CLOSURE );
return 1;
}
closure = current_closure;
}
else if ( type( car->data.atom->flags ) != ATOM_CLOSURE )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_CLOSURE );
return 1;
}
else
closure = car->data.atom->data.closure;
temp = make_stack();
if ( make_act_record( args->next, closure, temp, syntax, 1 ))
{
stack_free( temp );
return 1;
}
local_env = make_atom_from_act_record( temp );
current_closure = closure;
stop = 1;
tailcall = 1;
tailcall_syntax = syntax;
return 1;
}
int do_stat( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct stat st;
struct group *gp;
struct passwd *pw;
struct object *obj, *result;
obj = stack_pop( stack );
if ( stat( obj->data.atom->data.string->string, &st ) < 0 )
{
if ( errno == ENOENT || errno == EACCES || errno == ENOTDIR )
{
stack_push( stack, make_object());
setlist( ( *( struct object **)stack->top )->flags );
return 0;
}
fprintf( stderr, "%s: stat: %s.\n", syntax, strerror( errno ));
return 1;
}
result = make_object();
setlist( result->flags );
stack_push( stack, result );
pw = getpwuid( st.st_uid );
if ( pw == NULL )
obj = make_atom_from_number( st.st_uid );
else
obj = make_atom_from_string( pw->pw_name, strlen( pw->pw_name ));
result->data.head = obj;
gp = getgrgid( st.st_gid );
if ( gp == NULL )
obj->next = make_atom_from_number( st.st_gid );
else
obj->next = make_atom_from_string( gp->gr_name, strlen( gp->gr_name ));
obj->next->next = make_atom_from_number( st.st_atime );
obj->next->next->next= make_atom_from_number( st.st_mtime );
obj->next->next->next->next = make_atom_from_number( st.st_size );
}
return 0;
}
int do_mkdir( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *obj;
int mode;
mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
obj = ( struct object *)stack_pop( stack );
mode = mkdir( obj->data.atom->data.string->string, mode );
if ( mode < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_realpath( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *obj;
char real[ MAXPATHLEN + 1 ], *ptr = NULL;
obj = stack_pop( stack );
if ( *obj->data.atom->data.string->string == '\0' )
{
stack_push( stack, obj );
return 0;
}
ptr = expand_tilde( obj->data.atom->data.string->string );
if ( realpath( ptr, real ) == NULL )
stack_push( stack, make_atom_from_string( "", 0 ));
else
stack_push( stack, make_atom_from_string( real, strlen( real )));
free( ptr );
}
return 0;
}
int do_access( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
int mode;
struct object *obj1, *obj2;
obj2 = stack_pop( stack );
obj1 = stack_pop( stack );
mode = number( obj2->data.atom );
if ( mode != 0 && mode != 1 && mode != 2 )
{
fprintf( stderr, "%s: unrecognized mode: %d.\n",
syntax, mode );
return 1;
}
mode = ( mode ? ( mode == 1 ? W_OK : X_OK ) : R_OK );
mode = access( obj1->data.atom->data.string->string, mode );
stack_push( stack, make_atom_from_number( ( mode ? 0 : 1 )));
}
return 0;
}
void adjust_bookmarks( int start, int quantity )
{
int i, line;
struct stack *keys;
if ( buffer == NULL )
return;
keys = get_hash_keys( bookmarks );
for( i = 0; i < keys->used; ++i )
{
line = ( int )lookup_elt( bookmarks, ( int )keys->values[ i ] );
if ( line > 0 && line > start )
insert_elt( bookmarks,
( int )keys->values[ i ],
( struct object *)( line + quantity ) );
}
stack_free( keys );
}
void delete_bookmarks( int start, int end )
{
int i, line;
struct stack *keys;
if ( buffer == NULL )
return;
keys = get_hash_keys( bookmarks );
for( i = 0; i < keys->used; ++i )
{
line = ( int )lookup_elt( bookmarks, ( int )keys->values[ i ] );
if ( line > 0 && line >= start && line <= end )
insert_elt( bookmarks,
( int )keys->values[ i ],
( struct object *)-1 );
}
stack_free( keys );
}
int do_setmark( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_ATOM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
{
struct object *car1, *car2;
int line, last;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
line = number( car2->data.atom );
if ( do_lastline( syntax, NULL ))
return 1;
last = number( ( *( struct object **)stack->top )->data.atom );
stack_pop( stack );
if ( line < 0 || line > last )
{
fprintf( stderr, "%s: line %d out of range.\n", syntax,
number( car2->data.atom ));
return 1;
}
if ( numberp( car1->flags ) )
car1 = make_atom_from_number_for_hash_key( number( car1->data.atom ) );
insert_elt( bookmarks, car1->data.atom->id, ( struct object *)line );
}
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_getmark( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_ATOM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
if ( buffer == NULL )
{
fprintf( stderr, "%s: no buffer is open.\n", syntax );
return 1;
}
{
struct object *car;
int line;
car = stack_pop( stack );
if ( numberp( car->flags ))
car = make_atom_from_number_for_hash_key( number( car->data.atom ));
line = ( int )lookup_elt( bookmarks, car->data.atom->id );
stack_push( stack, make_atom_from_number( line ));
}
return 0;
}
void sigwinch_handler( int signo )
{
struct winsize winsize;
if ( ioctl( 1, TIOCGWINSZ, &winsize ) < 0 )
{
LINES = COLS = 0;
return;
}
LINES = winsize.ws_row;
COLS = winsize.ws_col;
#ifdef DEBUG
fprintf( stderr, "LINES = %d\nCOLS= %d\n", LINES, COLS );
#endif
sigwinch = 1;
}
int do_boldface( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
putp( bd );
fflush( stdout );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_normal( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
putp( me );
fflush( stdout );
stack_push( stack, make_atom_from_number( 1 ) );
return 0;
}
int do_pause( char *syntax, struct object *args )
{
struct object *car;
struct timeval timeval;
int arg1, fd, c, result, was_canon;
fd_set in_set;
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
arg1 = number( car->data.atom );
timeval.tv_sec = 0;
timeval.tv_usec = arg1;
was_canon = mode;
nocanon( syntax );
fd = 0;
FD_ZERO( &in_set );
FD_SET( fd, &in_set );
if(( result = select( fd + 1, &in_set, NULL, NULL, &timeval )) < 0 )
{
if ( errno != EINTR )
{
fprintf( stderr, "%s: select: %s.\n", syntax, strerror( errno ));
return 1;
}
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
if ( result == 0 )
{
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
if ( FD_ISSET( fd, &in_set ))
{
c = 0;
if ( read( fd, &c, 1 ) < 0 )
{
fprintf( stderr, "%s: read: %s.\n", syntax, strerror( errno ));
return 1;
}
pushed_back = ( int)c;
}
if ( was_canon )
canon( syntax );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_display( char *syntax, struct object *args )
{
struct object *car1, *car2, *car3;
int result, i, last, key, end, start, len, tabstop;
struct string *s;
if ( ( int )cl == -1 || ( int )ce == -1 || ( int )cm == -1 )
{
fprintf( stderr, "%s: terminal has insufficient capabilities.\n",
syntax );
return 1;
}
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)3 );
if ( check_args( syntax, args ))
return 1;
car3 = stack_pop( stack );
car2 = stack_pop( stack );
car1 = stack_pop( stack );
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if (( result = buffer->seq( buffer, &dbt_key, &dbt_value, R_LAST )) == -1 )
{
fprintf( stderr, "%s: db->seq: %s.\n", syntax, strerror( errno ));
return 1;
}
last = *( int *)dbt_key.data;
key = number( car1->data.atom );
if ( key < 0 || key > last )
{
fprintf( stderr, "%s: line %d out of range.\n", syntax, key );
return 1;
}
start = number( car2->data.atom );
if ( start < 0 )
{
fprintf( stderr, "%s: column %d out of range.\n", syntax, start );
return 1;
}
tabstop = number( car3->data.atom );
if ( tabstop < 0 )
{
fprintf( stderr, "%s: tabstop %d out of range.\n", syntax, tabstop );
return 1;
}
i = 0;
end = LINES - 1;
s = make_string();
if ( key > 0 && last )
while( key <= last && i < end )
{
putp( tgoto( cm, 0, i ));
putp( ce );
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
key_data = key;
if (( result = buffer->get( buffer, &dbt_key, &dbt_value, 0 )) < 0 )
{
fprintf( stderr, "%s: db->get: %s.\n", syntax, strerror( errno ));
string_free( s );
return 1;
}
else if ( result == 1 )
{
fprintf( stderr, "%s: db->get: key does not exist.\n", syntax );
string_free( s );
return 1;
}
{
int j, limit, offset;
char *ptr;
string_truncate( s );
ptr = ( char *)dbt_value.data;
len = dbt_value.size;
offset = 0;
for( j = 0; j < len; ++j )
{
if ( *ptr == '\t' )
{
int spaces;
spaces = tabstop - ( j + offset ) % tabstop;
offset += spaces - 1;
while( spaces-- )
string_append( s, ' ' );
}
else if ( *ptr != '\r' && *ptr != '\n' )
string_append( s, *ptr );
++ptr;
}
if ( start < s->used )
{
limit = MIN( s->used, start + COLS );
s->str[ limit ] = '\0';
fputs( &s->str[ start ], stdout );
}
}
++key;
++i;
}
while( i < end )
{
putp( tgoto( cm, 0, i ));
putp( ce );
putchar( '~' );
++i;
}
fflush( stdout );
string_free( s );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_scrollup( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( ( int )sf == -1 || ( int )sc == -1 )
{
fprintf( stderr, "%s: terminal has insufficient capabilities.\n",
syntax );
return 1;
}
putp( sc );
putp( tgoto( cm, 0, LINES - 1 ));
putp( sf );
putp( rc );
fflush( stdout );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_scrolldn( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( ( int )sr == -1 || ( int )sc == -1 )
{
fprintf( stderr, "%s: terminal has insufficient capabilities.\n",
syntax );
return 1;
}
putp( sc );
putp( tgoto( cm, 0, 0 ));
putp( sr );
putp( rc );
fflush( stdout );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_clearscreen( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( ( int)cl != -1 )
{
putp( cl );
fflush( stdout );
}
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_goto( char *syntax, struct object *args )
{
struct object *car1, *car2;
int y, x;
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
y = number( car1->data.atom );
x = number( car2->data.atom );
if ( y < 0 || y > LINES )
{
fprintf( stderr, "%s: line index %d out of range.\n",
syntax, y );
return 1;
}
if ( x < 0 || x > COLS )
{
fprintf( stderr, "%s: column index %d out of range.\n",
syntax, x );
return 1;
}
putp( tgoto( cm, x, y ));
fflush( stdout );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_clearline( char *syntax, struct object *args )
{
struct object *car1, *car2;
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( number( car1->data.atom ) < 0 ||
number( car1->data.atom ) > LINES - 1 )
{
fprintf( stderr, "%s: line %d out of range.\n", syntax,
number( car1->data.atom ));
return 1;
}
if ( number( car2->data.atom ) < 0 ||
number( car2->data.atom ) > COLS - 1 )
{
fprintf( stderr, "%s: column %d out of range.\n", syntax,
number( car2->data.atom ));
return 1;
}
putp( tgoto( cm, number( car2->data.atom ),
number( car1->data.atom )));
putp( ce );
fflush( stdout );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_hide( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
putp( vi );
fflush( stdout );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_show( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
putp( ve );
fflush( stdout );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_insertln( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( ( int )al == - 1 )
{
fprintf( stderr, "%s: terminal has insufficient capabilities.\n",
syntax );
return 1;
}
putp( al );
fflush( stdout );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_getchar( char *syntax, struct object *args )
{
int result, c, was_canon;
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( pushed_back >= 0 )
{
stack_push( stack, make_atom_from_number( pushed_back ));
pushed_back = -1;
return 0;
}
if (( was_canon = mode ))
nocanon( syntax );
fflush( stdout );
blocking_fd( 0 );
AGAIN:
c = 0;
result = read( 0, &c, 1 );
if ( result == 0 )
stack_push( stack, make_atom_from_number( -1 ));
else if ( result < 0 )
{
switch( errno )
{
case EINTR:
if ( !sigwinch )
goto AGAIN;
else
{
stack_push( stack, make_atom_from_number( -2 ));
sigwinch = 0;
}
break;
case EAGAIN:
goto AGAIN;
default:
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
}
}
else
stack_push( stack, make_atom_from_number( c ));
if ( was_canon )
canon( syntax );
return 0;
}
int do_pushback( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
car = stack_pop( stack );
pushed_back = number( car->data.atom );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_canon( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *) 0 );
if ( check_args( syntax, args ))
return 1;
canon( syntax );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_nocanon( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
nocanon( syntax );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_noprinter( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
printer = 0;
return 0;
}
int do_printer( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
printer = 1;
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_shexec( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
char *exec_args[ 4 ];
car = stack_pop( stack );
exec_args[ 0 ] = "/bin/sh";
exec_args[ 1 ] = "-c";
exec_args[ 2 ] = car->data.atom->data.string->string;
exec_args[ 3 ] = NULL;
fflush( stdout );
fflush( stderr );
execv( exec_args[ 0 ], exec_args );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
}
return 0;
}
int do_exec( char *syntax, struct object *args )
{
struct object *ptr;
char **exec_args;
int n;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, -1 );
return 1;
}
for( ptr = args, n = 1; ptr != NULL; ptr = ptr->next, ++n )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, n, -1 );
return 1;
}
if ( islist( ( *( struct object **)stack->top )->flags ) ||
numberp( ( *( struct object **)stack->top )->flags ) ||
type( ( *( struct object **)stack->top )->data.atom->flags ) != ATOM_STRING )
{
print_err( ERR_ARG_TYPE, syntax, n, ERR_STRING );
return 1;
}
}
exec_args = memory( n * sizeof( char * ) );
exec_args[ --n ] = NULL;
for( --n; n >= 0; --n )
{
ptr = stack_pop( stack );
exec_args[ n ] = ptr->data.atom->data.string->string;
}
fflush( stdout );
fflush( stderr );
execv( exec_args[ 0 ], exec_args );
free( exec_args );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
int do_truncate( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1;
car1 = stack_pop( stack );
if ( ftruncate( 1, number( car1->data.atom )) < 0 )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_symbolp( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
if ( islist( car->flags ) == 0 &&
numberp( car->flags ) == 0 &&
type( car->data.atom->flags ) == ATOM_SYMBOL )
stack_push( stack, make_atom_from_number( 1 ));
else
stack_push( stack, make_atom_from_number( 0 ));
}
return 0;
}
int do_regexpp( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
if ( islist( car->flags ) == 0 &&
numberp( car->flags ) == 0 &&
type( car->data.atom->flags ) == ATOM_REGEXP )
stack_push( stack, make_atom_from_number( 1 ));
else
stack_push( stack, make_atom_from_number( 0 ));
}
return 0;
}
int do_tablep( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
if ( islist( car->flags ) == 0 &&
numberp( car->flags ) == 0 &&
type( car->data.atom->flags ) == ATOM_TABLE )
stack_push( stack, make_atom_from_number( 1 ));
else
stack_push( stack, make_atom_from_number( 0 ));
}
return 0;
}
int do_stackp( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
if ( islist( car->flags ) == 0 &&
numberp( car->flags ) == 0 &&
type( car->data.atom->flags ) == ATOM_STACK )
stack_push( stack, make_atom_from_number( 1 ));
else
stack_push( stack, make_atom_from_number( 0 ));
}
return 0;
}
int do_intrinsicp( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
if ( islist( car->flags ) == 0 &&
numberp( car->flags ) == 0 &&
type( car->data.atom->flags ) == ATOM_INTRINSIC )
stack_push( stack, make_atom_from_number( 1 ));
else
stack_push( stack, make_atom_from_number( 0 ));
}
return 0;
}
int do_closurep( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
if ( islist( car->flags ) == 0 &&
numberp( car->flags ) == 0 &&
type( car->data.atom->flags ) == ATOM_CLOSURE )
stack_push( stack, make_atom_from_number( 1 ));
else
stack_push( stack, make_atom_from_number( 0 ));
}
return 0;
}
int do_macrop( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
if ( islist( car->flags ) == 0 &&
numberp( car->flags ) == 0 &&
type( car->data.atom->flags ) == ATOM_MACRO )
stack_push( stack, make_atom_from_number( 1 ));
else
stack_push( stack, make_atom_from_number( 0 ));
}
return 0;
}
int do_dynamic_let( char *syntax, struct object *args )
{
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, 0 );
return 1;
}
if ( islist( args->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_LIST );
return 1;
}
if ( args->data.head == NULL )
{
fprintf( stderr, "%s: argument 1 is the empty list.\n",
syntax );
return 1;
}
if ( args->next == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 2, 0 );
return 1;
}
if ( args->data.head == NULL )
{
fprintf( stderr, "%s: argument 1 is the empty list.\n", syntax );
return 1;
}
if ( args->data.head->next == NULL )
{
fprintf( stderr, "%s: element 1 of argument 1 contains only one sub-element.\n", syntax );
return 1;
}
if ( args->data.head->next->next != NULL )
{
fprintf( stderr, "%s: element 1 of argument 1 contains more than two sub-elements.\n", syntax );
return 1;
}
if ( islist( args->data.head->flags ) == 1 ||
numberp( args->data.head->flags ) ||
type( args->data.head->data.atom->flags ) != ATOM_SYMBOL )
{
fprintf( stderr, "%s: element 1 of argument 1 is not a symbol.\n", syntax );
return 1;
}
{
struct object *value, *old;
int result;
stack_push( stack, args->data.head->next );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: evaluation of expression to bind failed.\n", syntax );
return 1;
}
value = stack_pop( stack );
old = lookup_binding( args->data.head->data.atom->id );
insert_binding( args->data.head->data.atom->id, value );
if ( old != NULL )
stack_push( stack, old );
result = do_progn( syntax, args->next );
if ( old != NULL )
insert_binding( args->data.head->data.atom->id, old );
else
remove_binding( args->data.head->data.atom->id );
if ( result == 0 && old != NULL )
{
struct object *returned;
returned = stack_pop( stack );
stack_pop( stack );
stack_push( stack, returned );
}
return result;
}
}
int do_chmod( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
struct stat st;
mode_t newmode;
void *mode;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
mode = setmode( car1->data.atom->data.string->string );
if ( mode == NULL )
{
char buffer[ 256 ];
snprintf( buffer, sizeof( buffer ), "Invalid mode: %s",
car1->data.atom->data.string->string );
stack_push( stack, make_atom_from_string( buffer, strlen( buffer )));
return 0;
}
if ( stat( car2->data.atom->data.string->string, &st ) < 0 )
{
free( mode );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
newmode = getmode( mode, st.st_mode );
free( mode );
if ( chmod( car2->data.atom->data.string->string, newmode ) < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 1;
}
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_chown( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)3 );
if ( check_args( syntax, args ))
return 1;
{
char buffer[ 256 ];
struct object *car1, *car2, *car3;
int gid, uid;
car3 = stack_pop( stack );
car2 = stack_pop( stack );
car1 = stack_pop( stack );
gid = uid = -1;
if ( car1->data.atom->data.string->length )
{
struct passwd *pass;
if ( getuid() != 0 && geteuid() != 0 )
{
stack_push( stack, make_atom_from_string( "only root may change user", 25 ));
return 0;
}
pass = getpwnam( car1->data.atom->data.string->string );
if ( pass == NULL )
{
snprintf( buffer, sizeof( buffer ), "no such user: %s",
car1->data.atom->data.string->string );
stack_push( stack, make_atom_from_string( buffer, strlen( buffer )));
return 0;
}
uid = pass->pw_uid;
}
if ( car2->data.atom->data.string->length == 0 || uid == -1 )
{
struct stat st;
if ( stat( car3->data.atom->data.string->string, &st ) < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
if ( uid == -1 )
uid = st.st_uid;
else
gid = st.st_gid;
}
if ( car2->data.atom->data.string->length )
{
struct group *group;
if (( group = getgrnam( car2->data.atom->data.string->string )) == NULL )
{
snprintf( buffer, sizeof( buffer ), "no such group: %s",
car2->data.atom->data.string->string );
stack_push( stack, make_atom_from_string( buffer, strlen( buffer )));
return 0;
}
gid = group->gr_gid;
}
if ( chown( car3->data.atom->data.string->string, uid, gid ) < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_clear( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STACK );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
int n;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
n = number( car2->data.atom );
if ( n < 0 )
{
fprintf( stderr, "%s: argument 2 is negative number.\n", syntax );
return 1;
}
while( n-- && car1->data.atom->data.stack->used )
stack_pop( car1->data.atom->data.stack );
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_basename( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void*)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
char *ptr;
car = stack_pop( stack );
if (( ptr = basename( car->data.atom->data.string->string )) == NULL )
stack_push( stack, make_atom_from_string( "", 0 ));
else
stack_push( stack, make_atom_from_string( ptr, strlen( ptr )));
}
return 0;
}
int do_dirname( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void*)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
char *ptr;
car = stack_pop( stack );
if (( ptr = dirname( car->data.atom->data.string->string )) == NULL )
stack_push( stack, make_atom_from_string( "", 0 ));
else
stack_push( stack, make_atom_from_string( ptr, strlen( ptr )));
}
return 0;
}
int do_checkpass( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
struct passwd *passwd;
char *encrypted;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if (( passwd = getpwnam( car1->data.atom->data.string->string )) == NULL )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
if (( encrypted = crypt( car2->data.atom->data.string->string,
passwd->pw_passwd )) == NULL )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
if ( strcmp( passwd->pw_passwd, encrypted ))
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_setuid( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
struct passwd *passwd;
car = stack_pop( stack );
if (( passwd = getpwnam( car->data.atom->data.string->string )) == NULL )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else if ( setuid( passwd->pw_uid ) < 0 )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_getuid( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
{
struct object *result;
struct passwd *passwd;
result = make_object();
setlist( result->flags );
stack_push( stack, result );
if (( passwd = getpwuid( getuid() )) == NULL )
return 0;
result->data.head = make_atom_from_string( passwd->pw_name, strlen( passwd->pw_name ));
result->data.head->next = make_atom_from_number( passwd->pw_uid );
}
return 0;
}
int do_getgid( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
{
struct object *result;
struct group *gp;
result = make_object();
setlist( result->flags );
stack_push( stack, result );
if (( gp = getgrgid( getgid() )) == NULL )
return 0;
result->data.head = make_atom_from_string( gp->gr_name, strlen( gp->gr_name ));
result->data.head->next = make_atom_from_number( gp->gr_gid );
}
return 0;
}
int do_geteuid( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
{
struct object *result;
struct passwd *passwd;
result = make_object();
setlist( result->flags );
stack_push( stack, result );
if (( passwd = getpwuid( geteuid() )) == NULL )
return 0;
result->data.head = make_atom_from_string( passwd->pw_name, strlen( passwd->pw_name ));
result->data.head->next = make_atom_from_number( passwd->pw_uid );
}
return 0;
}
int do_seteuid( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
struct passwd *passwd;
car = stack_pop( stack );
if (( passwd = getpwnam( car->data.atom->data.string->string )) == NULL )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else if ( seteuid( passwd->pw_uid ) < 0 )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_seek( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)3 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2, *car3;
char *w;
int fd, offset, whence;
car3 = stack_pop( stack );
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if (( fd = number( car1->data.atom )) != 0 && fd != 2 && fd != 1 )
{
fprintf( stderr, "%s: descriptor argument out of range: %d.\n", syntax, fd );
return 1;
}
offset = number( car2->data.atom );
w = car3->data.atom->data.string->string;
if ( strcmp( w, "SEEK_SET") == 0 )
whence = SEEK_SET;
else if ( strcmp( w, "SEEK_CUR" ) == 0 )
whence = SEEK_CUR;
else if ( strcmp( w, "SEEK_END" ) == 0 )
whence = SEEK_END;
else
{
fprintf( stderr, "%s: unrecognized whence argument: %s.\n", syntax, w );
return 1;
}
if ( fd == 0 )
{
if (( offset = lseek( fd, offset, whence )) < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
}
else
{
if (( offset = fseek( ( fd == 1 ? stdout : stderr ), offset, whence ))
< 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
}
stack_push( stack, make_atom_from_number( offset ));
}
return 0;
}
struct object *make_atom_directly_from_string( char *s, int len )
{
struct atom *entry;
struct object *object;
entry = get_id( s, len, 0 );
if ( entry->flags == 0 )
{
entry->flags = ATOM_STRING;
entry->data.string = memory( sizeof( struct lstring ));
entry->data.string->length = len - 1;
entry->data.string->string = &entry->syntax[ 1 ];
}
else
free( s );
object = make_object();
object->data.atom = entry;
return object;
}
int do_getchars( char *syntax, struct object *args )
{
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 1, 0 );
return 1;
}
else if ( args->next == NULL )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
}
else if ( args->next->next != NULL )
{
print_err( ERR_MORE_ARGS, syntax, 2, 0 );
return 1;
}
else
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
}
{
struct object *car;
char *buffer, *ptr;
int total, timeout, returned;
struct itimerval value;
timeout = 0;
if ( args->next != NULL )
{
car = stack_pop( stack );
timeout = number( car->data.atom );
}
car = stack_pop( stack );
total = number( car->data.atom );
if ( total == 0 )
{
stack_push( stack, make_atom_from_string( "", 0 ));
return 0;
}
if ( total < 0 )
{
fprintf( stderr, "%s: argument 1 < 0.\n", syntax );
return 1;
}
buffer = memory( total + 2 );
buffer[ 0 ] = '"';
ptr = &buffer[ 1 ];
AGAIN:
if ( timeout )
{
value.it_interval.tv_sec = 0;
value.it_interval.tv_usec = 0;
value.it_value.tv_sec = timeout;
value.it_value.tv_usec = 0;
setitimer( ITIMER_REAL, &value, NULL );
}
returned = read( 0, ptr, total );
if ( timeout )
{
value.it_value.tv_sec = 0;
value.it_value.tv_usec = 0;
setitimer( ITIMER_REAL, &value, NULL );
}
if ( returned < 0 )
{
if ( sigalrm )
{
if ( ptr != &buffer[ 1 ] )
{
*ptr = '\0';
stack_push( stack, make_atom_directly_from_string( buffer, ptr - buffer ));
}
else
{
stack_push( stack, make_atom_from_string( "", -1 ));
free( buffer );
}
sigalrm = 0;
return 0;
}
else if ( errno == EINTR || errno == EAGAIN )
goto AGAIN;
free( buffer );
fprintf( stderr, "%s: read: %s.\n", syntax, strerror( errno ));
return 1;
}
if ( returned == 0 )
{
if ( ptr != &buffer[ 1 ] )
{
*ptr = '\0';
stack_push( stack, make_atom_directly_from_string( buffer, ptr - buffer ));
}
else
{
stack_push( stack, make_atom_from_number( 0 ));
free( buffer );
}
return 0;
}
if ( returned < total )
{
ptr = &ptr[ returned ];
total -= returned;
goto AGAIN;
}
returned += ptr - buffer;
buffer[ returned ] = '\0';
stack_push( stack, make_atom_directly_from_string( buffer, returned ));
}
return 0;
}
int do_readlock( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
{
int result;
if (( result = flock( 0, LOCK_SH | LOCK_NB )) < 0 )
{
if ( errno == EWOULDBLOCK )
stack_push( stack, make_atom_from_number( 0 ));
else
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_writelock( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
{
int result;
if (( result = flock( 1, LOCK_EX | LOCK_NB )) < 0 )
{
if ( errno == EWOULDBLOCK )
stack_push( stack, make_atom_from_number( 0 ));
else
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_unlock( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
int result, fd;
car = stack_pop( stack );
fd = number( car->data.atom );
if ( fd != 0 && fd != 1 )
{
fprintf( stderr, "%s: invalid descriptor: %d.\n", syntax, fd );
return 1;
}
if (( result = flock( fd, LOCK_UN | LOCK_NB )) < 0 )
{
if ( errno == EWOULDBLOCK )
stack_push( stack, make_atom_from_number( 0 ));
else
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_hostname( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
{
char hostname[ MAXHOSTNAMELEN + 1 ];
if ( gethostname( hostname, MAXHOSTNAMELEN ) < 0 )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else
stack_push( stack, make_atom_from_string( hostname, strlen( hostname )));
}
return 0;
}
int do_symlink( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( symlink( car1->data.atom->data.string->string,
car2->data.atom->data.string->string ) < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
}
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_gecos( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct passwd *passwd;
struct object *car;
car = stack_pop( stack );
if (( passwd = getpwnam( car->data.atom->data.string->string )) == NULL )
{
stack_push( stack, make_atom_from_string( "", 0 ));
return 0;
}
stack_push( stack, make_atom_from_string( passwd->pw_gecos, strlen( passwd->pw_gecos )));
}
return 0;
}
struct object *make_empty_list()
{
struct object *obj;
obj = make_object();
setlist( obj->flags );
return obj;
}
int do_record( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car, **result, **ptr;
int size, i;
car = stack_pop( stack );
size = number( car->data.atom );
if ( size < 1 )
{
fprintf( stderr, "%s: argument 1 is less than 1.\n", syntax );
return 1;
}
result = memory( ( size * sizeof( struct object * )) + 1 );
ptr = result;
*ptr++ = ( struct object *)size;
for( i = 0; i < size; ++i )
*ptr++ = make_empty_list();
stack_push( stack, make_atom_from_record( result ));
}
return 0;
}
int do_getfield( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_RECORD );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
int idx;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
idx = number( car2->data.atom );
if ( idx < 0 )
{
fprintf( stderr, "%s: index %d is less than 0.\n", syntax, idx );
return 1;
}
else if ( idx >= *( int *)car1->data.atom->data.record )
{
fprintf( stderr, "%s: index %d beyond end of record.\n", syntax, idx );
return 1;
}
stack_push( stack, ( ( struct object **)car1->data.atom->data.record )[ idx + 1 ] );
}
return 0;
}
int do_setfield( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_RECORD );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)3 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2, *car3;
int idx;
car3 = stack_pop( stack );
car2 = stack_pop( stack );
car1 = stack_pop( stack );
idx = number( car2->data.atom );
if ( idx < 0 )
{
fprintf( stderr, "%s: index %d is less than 0.\n", syntax, idx );
return 1;
}
else if ( idx >= *( int *)car1->data.atom->data.record )
{
fprintf( stderr, "%s: index %d beyond end of record.\n", syntax, idx );
return 1;
}
(( struct object **)car1->data.atom->data.record )[ idx + 1 ] = car3;
stack_push( stack, car3 );
}
return 0;
}
int do_extend( char *syntax, struct object *args )
{
if ( local_env == NULL )
{
fprintf( stderr, "%s: no local environment is active.\n", syntax );
return 1;
}
stack_push( arg_stack, ( void *)ERR_SYMBOL );
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
stack_push( local_env->data.atom->data.act_record, car2 );
stack_push( local_env->data.atom->data.act_record, ( void *)car1->data.atom->id );
stack_push( stack, car2 );
}
return 0;
}
int do_gc( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
gc = 1;
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_recordp( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)-1 );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
if ( islist( car->flags ) == 00 &&
numberp( car->flags ) == 0 &&
type( car->data.atom->flags ) == ATOM_RECORD )
stack_push( stack, make_atom_from_number( 1 ));
else
stack_push( stack, make_atom_from_number( 0 ));
}
return 0;
}
int cfor( struct object *args )
{
int i, j;
struct object *loop, *body, *test, *final, *ptr, *result, *after;
loop = args->data.head;
body = args->next;
if ( loop->next == NULL ||
islist( loop->next->flags ) == 0 ||
loop->next->next == NULL ||
islist( loop->next->next->flags ) == 0 )
{
fprintf( stderr, "for: if the first element of the first argument list is itself a list,\n"
" then all of the first argument list's elements must also be lists.\n" );
return 1;
}
if ( loop->next->next->next != NULL )
{
fprintf( stderr, "for: first argument list has more than 3 elements.\n" );
return 1;
}
if ( loop->next->data.head == NULL )
{
fprintf( stderr, "for: test/return list, is the empty list.\n" );
return 1;
}
test = loop->next->data.head;
final = test->next;
after = loop->next->next->data.head;
if ( loop->data.head != NULL )
{
for( i = 1, ptr = loop->data.head; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "for: evaluation of initialization expression %d failed.\n", i );
return 1;
}
stack_pop( stack );
}
}
for( ; ; )
{
stack_push( stack, test );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "for: evaluation of test expression failed.\n" );
return 1;
}
result = stack_pop( stack );
j = stack->used;
if (( islist( result->flags ) == 1 && result->data.head == NULL ) ||
result->data.atom == NULL ||
result->data.atom == empty->data.atom )
{
for( i = 1, ptr = final; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "for: evaluation of return expression %d failed.\n", i );
return 1;
}
result = stack_pop( stack );
}
stack_push( stack, result );
break;
}
for( i = 1, ptr = body; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "for: evaluation of body form %d failed.\n", i );
if ( next_iteration )
{
next_iteration = 0;
stop = 0;
thrown = NULL;
stack_truncate( stack, stack->used - j );
goto CONTINUE;
}
return 1;
}
stack_pop( stack );
}
CONTINUE:
if ( after != NULL )
for( i = 1, ptr = after; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "for: evaluation of after expression %d failed.\n", i );
return 1;
}
stack_pop( stack );
}
}
return 0;
}
int do_for( char *syntax, struct object *args )
{
struct object *symbol, *from, *to, *incr;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 1, 0 );
return 1;
}
if ( islist( args->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_LIST );
return 1;
}
if ( args->data.head == NULL )
{
fprintf( stderr, "%s: argument 1 is empty list.\n", syntax );
return 1;
}
if ( args->next == NULL )
{
fprintf( stderr, "%s: missing body expressions.\n", syntax );
return 1;
}
/*
* if the first element is a list, try to execute a c-like for loop.
*/
if ( islist( args->data.head->flags ) )
return cfor( args );
if ( numberp( args->data.head->flags ) ||
type( args->data.head->data.atom->flags ) != ATOM_SYMBOL )
{
fprintf( stderr, "%s: element 1 of argument 1 must be a symbol.\n", syntax );
return 1;
}
symbol = args->data.head;
from = args->data.head->next;
if ( from == NULL )
{
fprintf( stderr, "%s: range elements missing from argument 1.\n", syntax );
return 1;
}
to = from->next;
if ( to == NULL )
{
fprintf( stderr, "%s: end value of range missing from argument 1.\n", syntax );
return 1;
}
incr = to->next;
if ( incr != NULL && incr->next != NULL )
{
fprintf( stderr, "%s: too many elements in argument 1.\n", syntax );
return 1;
}
stack_push( stack, from );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: error evaluating \"from\" value in argument 1.\n", syntax );
return 1;
}
stack_push( stack, to );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: error evaluating \"to\" value in argument 1.\n", syntax );
return 1;
}
if ( incr != NULL )
{
stack_push( stack, incr );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: error evaluation \"increment\" value in argument 1.\n", syntax );
return 1;
}
incr = stack_pop( stack );
}
to = stack_pop( stack );
from = stack_pop( stack );
if ( islist( from->flags ) || numberp( from->flags ) == 0 )
{
fprintf( stderr, "%s: \"from\" value not a number.\n", syntax );
return 1;
}
if ( islist( to->flags ) || numberp( to->flags ) == 0 )
{
fprintf( stderr, "%s: \"to\" value not a number.\n", syntax );
return 1;
}
if ( incr != NULL && ( islist( incr->flags ) || numberp( incr->flags ) == 0 ))
{
fprintf( stderr, "%s: \"increment\" value not a number.\n", syntax );
return 1;
}
{
int start, end, inc, idx, no_env, i, old;
struct object *ptr, *result = NULL, **act_ptr;
start = number( from->data.atom );
end = number( to->data.atom );
inc = ( start <= end ? 1 : -1 );
if ( incr != NULL )
inc *= abs( number( incr->data.atom ) );
no_env = ( local_env == NULL ? 1 : 0 );
if ( no_env )
{
local_env = make_atom_from_act_record( make_stack() );
stack_push( local_env->data.atom->data.act_record, NULL );
old = -1;
}
else
old = local_env->data.atom->data.act_record->used;
stack_push( local_env->data.atom->data.act_record, make_atom_from_number( start ));
act_ptr = ( struct object **)local_env->data.atom->data.act_record->top;
stack_push( local_env->data.atom->data.act_record, ( void *)symbol->data.atom->id );
idx = start;
while (( inc < 0 ? ( idx >= end ) : ( idx <= end )))
{
for( i = 1, ptr = args->next; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( next_iteration )
{
next_iteration = 0;
stop = 0;
thrown = NULL;
break;
}
else
{
if ( !stop )
fprintf( stderr, "%s: error evaluating body expression %d.\n",
syntax, i );
result = NULL;
goto ERROR;
}
}
result = stack_pop( stack );
}
if ( numberp( ( *act_ptr )->flags ) == 0 )
{
fprintf( stderr, "%s: index variable rebound to non-number.\n", syntax );
result = NULL;
goto ERROR;
}
( *act_ptr )->data.atom = ( struct atom *)( idx = number( ( *act_ptr )->data.atom ) + inc );
}
ERROR:
if ( no_env )
local_env = NULL;
else
{
while( local_env->data.atom->data.act_record->used > old )
stack_pop( local_env->data.atom->data.act_record );
}
if ( result == NULL )
return 1;
stack_push( stack, result );
}
return 0;
}
int do_iterate( char *syntax, struct object *args )
{
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, 0 );
return 1;
}
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, 0 );
return 1;
}
{
struct object *ptr, *result = NULL;
int i, j;
result = stack_pop( stack );
if ( numberp( result->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_FIXNUM );
return 1;
}
for( j = abs( number( result->data.atom ) ); j; --j )
{
for( i = 1, ptr = args->next; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( next_iteration )
{
next_iteration = 0;
stop = 0;
thrown = NULL;
break;
}
else
{
if ( !stop )
fprintf( stderr, "%s: error evaluating body expression %d.\n",
syntax, i );
return 1;
}
}
result = stack_pop( stack );
}
}
stack_push( stack, result );
}
return 0;
}
int do_dynamic_extent( char *syntax, struct object *args )
{
if ( args == NULL )
stack_push( stack, make_atom_from_number( 1 ));
else if ( local_env == NULL )
{
fprintf( stderr, "%s: no local environment is active.\n", syntax );
return 1;
}
else
{
int level, i;
struct object *ptr, *result = NULL;
level = local_env->data.atom->data.act_record->used;
for( i = 1, ptr = args; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: error evaluating body expression %d.\n",
syntax, i );
result = NULL;
goto ERROR;
}
result = stack_pop( stack );
}
ERROR:
stack_truncate( local_env->data.atom->data.act_record,
local_env->data.atom->data.act_record->used - level );
if ( result == NULL )
return 1;
stack_push( stack, result );
}
return 0;
}
int do_timediff( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
int time1, time2;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
time1 = atoi( car1->data.atom->data.string->string );
time2 = atoi( car2->data.atom->data.string->string );
stack_push( stack, make_atom_from_number( time1 - time2 ));
}
return 0;
}
int do_timethen( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
int then;
time_t t;
struct object *car;
char buffer[ 32 ];
car = stack_pop( stack );
then = number( car->data.atom );
if ( time( &t ) < 0 )
{
fprintf( stderr, "%s: time(): %s\n.", syntax, strerror( errno ));
return 1;
}
snprintf( buffer, sizeof( buffer ), "%ld", ( long int )( t + then ));
stack_push( stack, make_atom_from_string( buffer, -1 ));
}
return 0;
}
int do_inc( char *syntax, struct object *args )
{
struct object *symbol, *val;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, 0 );
return 1;
}
symbol = args;
if ( islist( symbol->flags ) ||
numberp( symbol->flags ) ||
type( symbol->data.atom->flags ) != ATOM_SYMBOL )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_SYMBOL );
return 1;
}
val = NULL;
if ( args->next )
{
if ( args->next->next )
{
print_err( ERR_MORE_ARGS, syntax, 2, 0 );
return 1;
}
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, 0 );
return 1;
}
val = stack_pop( stack );
if ( islist( val->flags ) ||
numberp( val->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 2, ERR_FIXNUM );
return 1;
}
}
{
int local;
struct object *current;
local = 1;
if (( current = lookup_local( symbol->data.atom->id )) == NULL )
{
local = 0;
current = lookup_binding( symbol->data.atom->id );
}
if ( current == NULL )
{
fprintf( stderr, "%s: symbol %s not bound.\n", syntax,
symbol->data.atom->syntax );
return 1;
}
if ( islist( current->flags ) ||
numberp( current->flags ) == 0 )
{
fprintf( stderr, "%s: symbol %s is not bound to a number.\n", syntax,
symbol->data.atom->syntax );
return 1;
}
stack_push( stack,
make_atom_from_number(
( val == NULL ? 1 : number( val->data.atom )) +
number( current->data.atom ) ));
if ( local )
set_local( symbol->data.atom->id, *stack->top );
else
insert_binding( symbol->data.atom->id, *stack->top );
}
return 0;
}
int do_dec( char *syntax, struct object *args )
{
struct object *symbol, *val;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, 0 );
return 1;
}
symbol = args;
if ( islist( symbol->flags ) ||
numberp( symbol->flags ) ||
type( symbol->data.atom->flags ) != ATOM_SYMBOL )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_SYMBOL );
return 1;
}
val = NULL;
if ( args->next )
{
if ( args->next->next )
{
print_err( ERR_MORE_ARGS, syntax, 2, 0 );
return 1;
}
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, 0 );
return 1;
}
val = stack_pop( stack );
if ( islist( val->flags ) ||
numberp( val->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 2, ERR_FIXNUM );
return 1;
}
}
{
int local;
struct object *current;
local = 1;
if (( current = lookup_local( symbol->data.atom->id )) == NULL )
{
local = 0;
current = lookup_binding( symbol->data.atom->id );
}
if ( current == NULL )
{
fprintf( stderr, "%s: symbol %s not bound.\n", syntax,
symbol->data.atom->syntax );
return 1;
}
if ( islist( current->flags ) ||
numberp( current->flags ) == 0 )
{
fprintf( stderr, "%s: symbol %s is not bound to a number.\n", syntax,
symbol->data.atom->syntax );
return 1;
}
stack_push( stack,
make_atom_from_number(
number( current->data.atom ) -
( val == NULL ? 1 : number( val->data.atom ))));
if ( local )
set_local( symbol->data.atom->id, *stack->top );
else
insert_binding( symbol->data.atom->id, *stack->top );
}
return 0;
}
int do_setq( char *syntax, struct object *args )
{
struct object *symbol;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, 0 );
return 1;
}
if ( args->next == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 2, 0 );
return 1;
}
if ( args->next->next )
{
print_err( ERR_MORE_ARGS, syntax, 2, 0 );
return 1;
}
symbol = args;
if ( islist( symbol->flags ) ||
numberp( symbol->flags ) ||
type( symbol->data.atom->flags ) != ATOM_SYMBOL )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_SYMBOL );
return 1;
}
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, 0 );
return 1;
}
if ( lookup_local( symbol->data.atom->id ) != NULL )
set_local( symbol->data.atom->id, *stack->top );
else
insert_binding( symbol->data.atom->id, *stack->top );
return 0;
}
int do_gc_freq( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
int freq, old;
car = stack_pop( stack );
freq = number( car->data.atom );
if ( freq < 0 || freq > INT_MAX )
{
fprintf( stderr, "%s: argument out of range.\n", syntax );
return 1;
}
old = gc_frequency;
gc_frequency = freq;
gc_on = ( freq ? 1 : 0 );
stack_push( stack, make_atom_from_number( old ));
}
return 0;
}
int do_child_eof( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( child_pid == -1 )
{
fprintf( stderr, "%s: an inferior process is not running.\n", syntax );
return 1;
}
else if ( child_eof )
{
fprintf( stderr, "%s: child_eof has already been invoked on the connection.\n", syntax );
return 1;
}
else if ( shutdown( child_fd, SHUT_WR ) < 0 )
{
fprintf( stderr, "%s: shutdown(): %s.\n", syntax, strerror( errno ));
return 1;
}
child_eof = 1;
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_crypt( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *obj;
char *str, *encrypted;
obj = stack_pop( stack );
str = str_dup( obj->data.atom->data.string->string, obj->data.atom->data.string->length );
encrypted = crypt( str, str );
free( str );
if ( encrypted == NULL )
{
fprintf( stderr, "%s: crypt: crypt() failed.\n", syntax );
return 1;
}
stack_push( stack, make_atom_from_string( encrypted, -1 ) );
}
return 0;
}
int do_loop( char *syntax, struct object *args )
{
struct object *ptr, *result = NULL;
int i;
if ( args == NULL )
{
fprintf( stderr, "%s: missing body.\n", syntax );
return 1;
}
for( ; ; )
{
for( i = 1, ptr = args; ptr != NULL; ptr = ptr->next, ++i )
{
stack_push( stack, ptr );
if ( evaluate() )
{
if ( next_iteration )
{
next_iteration = 0;
stop = 0;
thrown = NULL;
break;
}
else
{
if ( !stop )
fprintf( stderr, "%s: error evaluating body expression %d.\n",
syntax, i );
return 1;
}
}
result = stack_pop( stack );
}
}
/* not reached */
stack_push( stack, result );
return 0;
}
int do_date2days( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)3 );
if ( check_args( syntax, args ))
return 1;
{
struct date dt;
struct object *obj;
int days;
obj = stack_pop( stack );
dt.d = number( obj->data.atom );
obj = stack_pop( stack );
dt.m = number( obj->data.atom );
obj = stack_pop( stack );
dt.y = number( obj->data.atom );
if ( dt.y < 0 )
{
fprintf( stderr, "%s: year value less than 0: %d.\n", syntax, dt.y );
return 1;
}
else if ( dt.m > 12 || dt.m < 1 )
{
fprintf( stderr, "%s: month value out of range: %d.\n", syntax, dt.m );
return 1;
}
else if ( dt.d < 1 )
{
fprintf( stderr, "%s: day value out of range: %d.\n", syntax, dt.d );
return 1;
}
else if ( dt.m == 1 || dt.m == 3 || dt.m == 5 || dt.m == 7 ||
dt.m == 8 || dt.m == 10 || dt.m == 12 )
{
if ( dt.d > 31 )
{
fprintf( stderr, "%s: day value out of range for month: %d.\n", syntax, dt.d );
return 1;
}
}
else if ( dt.d > 30 )
{
fprintf( stderr, "%s: day value out of range for month: %d.\n", syntax, dt.d );
return 1;
}
if (( days = ndaysg( &dt )) < 0 )
{
fprintf( stderr, "%s: ndaysg() returned an error.\n", syntax );
return 1;
}
stack_push( stack, make_atom_from_number( days ));
}
return 0;
}
int do_days2date( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct date dt;
struct object *obj;
obj = stack_pop( stack );
if ( number( obj->data.atom ) < 0 )
{
fprintf( stderr, "%s: argument less than 0: %d.\n", syntax, number( obj->data.atom ));
return 1;
}
if ( gdate( number( obj->data.atom ), &dt ) == NULL )
{
fprintf( stderr, "%s: dateg() returned an error.\n", syntax );
return 1;
}
obj = make_object();
setlist( obj->flags );
obj->data.head = make_atom_from_number( dt.y );
obj->data.head->next = make_atom_from_number( dt.m );
obj->data.head->next->next = make_atom_from_number( dt.d );
stack_push( stack, obj );
}
return 0;
}
int do_week( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *obj;
int year, wk;
obj = stack_pop( stack );
if (( wk = week( number( obj->data.atom ), &year )) < 0 )
{
fprintf( stderr, "%s: week() returned an error.\n", syntax );
return 1;
}
obj = make_object();
setlist( obj->flags );
obj->data.head = make_atom_from_number( year );
obj->data.head->next = make_atom_from_number( wk );
stack_push( stack, obj );
}
return 0;
}
int do_weekday( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
static char *dtable[] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
struct object *obj;
int wkday;
obj = stack_pop( stack );
if (( wkday = weekday( number( obj->data.atom ))) < 0 )
{
fprintf( stderr, "%s: weekday() returned an error.\n", syntax );
return 1;
}
obj = make_object();
setlist( obj->flags );
obj->data.head = make_atom_from_number( ( wkday == 6 ? 0 : wkday % 6 + 1 ));
obj->data.head->next = make_atom_from_string( dtable[ wkday ], -1 );
stack_push( stack, obj );
}
return 0;
}
int do_date2time( char *syntax, struct object *args )
{
int hour, min, sec;
hour = min = sec = 0;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, 0 );
return 1;
}
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, 0 );
return 1;
}
if ( args->next == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 2, 0 );
return 1;
}
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, 0 );
return 1;
}
if ( args->next->next == NULL )
{
print_err( ERR_MISSING_ARG, syntax, 3, 0 );
return 1;
}
stack_push( stack, args->next->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 3, 0 );
return 1;
}
if ( args->next->next->next != NULL )
{
hour = 1;
stack_push( stack, args->next->next->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 4, 0 );
return 1;
}
if ( args->next->next->next->next != NULL )
{
min = 1;
stack_push( stack, args->next->next->next->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 5, 0 );
return 1;
}
if ( args->next->next->next->next->next != NULL )
{
sec = 1;
stack_push( stack, args->next->next->next->next->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 6, 0 );
return 1;
}
if ( args->next->next->next->next->next->next != NULL )
{
print_err( ERR_MORE_ARGS, syntax, 6, 0 );
return 1;
}
}
}
}
{
struct object *obj;
char buffer[ 32 ];
time_t t;
struct tm tm, *lt;
/* Use localtime to fill in tm.gmtoff */
t = time( NULL );
if (( lt = localtime( &t )) == NULL )
{
fprintf( stderr, "%s: localtime returned an error.\n", syntax );
return 1;
}
tm = *lt;
if ( sec )
{
obj = stack_pop( stack );
if ( numberp( obj->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 6, ERR_FIXNUM );
return 1;
}
tm.tm_sec = number( obj->data.atom );
}
else
tm.tm_sec = 0;
if ( min )
{
obj = stack_pop( stack );
if ( numberp( obj->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 5, ERR_FIXNUM );
return 1;
}
tm.tm_min = number( obj->data.atom );
}
else
tm.tm_min = 0;
if ( hour )
{
obj = stack_pop( stack );
if ( numberp( obj->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 4, ERR_FIXNUM );
return 1;
}
tm.tm_hour = number( obj->data.atom );
}
else
tm.tm_hour = 0;
tm.tm_isdst = -1;
obj = stack_pop( stack );
if ( numberp( obj->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 3, ERR_FIXNUM );
return 1;
}
tm.tm_mday = number( obj->data.atom );
obj = stack_pop( stack );
if ( numberp( obj->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 2, ERR_FIXNUM );
return 1;
}
tm.tm_mon = number( obj->data.atom ) - 1;
obj = stack_pop( stack );
if ( numberp( obj->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_FIXNUM );
return 1;
}
tm.tm_year = number( obj->data.atom ) - 1900;
if ( tm.tm_year < 70 )
{
fprintf( stderr, "%s: year value less than 1970: %d.\n", syntax, tm.tm_year + 1900 );
return 1;
}
else if ( tm.tm_mon > 11 || tm.tm_mon < 0 )
{
fprintf( stderr, "%s: month value out of range: %d.\n", syntax, tm.tm_mon + 1 );
return 1;
}
else if ( tm.tm_mday < 1 )
{
fprintf( stderr, "%s: day value out of range: %d.\n", syntax, tm.tm_mday );
return 1;
}
else if ( tm.tm_mon == 0 || tm.tm_mon == 2 || tm.tm_mon == 4 || tm.tm_mon == 6 ||
tm.tm_mon == 7 || tm.tm_mon == 9 || tm.tm_mon == 11 )
{
if ( tm.tm_mday > 31 )
{
fprintf( stderr, "%s: day value out of range for month: %d.\n", syntax, tm.tm_mday );
return 1;
}
}
else if ( tm.tm_mday > 30 )
{
fprintf( stderr, "%s: day value out of range for month: %d.\n", syntax, tm.tm_mday );
return 1;
}
else if ( tm.tm_hour < 0 || tm.tm_hour > 23 )
{
fprintf( stderr, "%s: hour value out of range: %d.\n", syntax, tm.tm_hour );
return 1;
}
else if ( tm.tm_min < 0 || tm.tm_min > 59 )
{
fprintf( stderr, "%s: minute value out of range: %d.\n", syntax, tm.tm_min );
return 1;
}
else if ( tm.tm_sec < 0 || tm.tm_sec > 59 )
{
fprintf( stderr, "%s: seconds value out of range: %d.\n", syntax, tm.tm_sec );
return 1;
}
if (( t = mktime( &tm )) < 0 )
{
fprintf( stderr, "%s: mktime() returned an error.\n", syntax );
return 1;
}
snprintf( buffer, sizeof( buffer ), "%ld", ( long int)t );
stack_push( stack, make_atom_from_string( buffer, -1 ));
}
return 0;
}
int broken_time( char *syntax, struct object *args, int utc )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *obj;
struct tm *tm;
time_t t;
obj = stack_pop( stack );
t = atol( obj->data.atom->data.string->string );
if (( tm = ( utc ? gmtime( &t ) : localtime( &t ))) == NULL )
{
fprintf( stderr, "%s: %s returned an error.\n", syntax,
( utc ? "gmtime()" : "localtime()" ));
return 1;
}
obj = make_object();
setlist( obj->flags );
obj->data.head = make_atom_from_number( tm->tm_year + 1900 );
obj->data.head->next = make_atom_from_number( tm->tm_mon + 1 );
obj->data.head->next->next = make_atom_from_number( tm->tm_mday );
obj->data.head->next->next->next = make_atom_from_number( tm->tm_hour );
obj->data.head->next->next->next->next = make_atom_from_number( tm->tm_min );
obj->data.head->next->next->next->next->next = make_atom_from_number( tm->tm_sec );
stack_push( stack, obj );
}
return 0;
}
int do_localtime( char *syntax, struct object *args )
{
return broken_time( syntax, args, 0 );
}
int do_utctime( char *syntax, struct object *args )
{
return broken_time( syntax, args, 1 );
}
int do_month( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
static char *months[] = { "January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December" };
struct object *obj;
int m;
obj = stack_pop( stack );
m = number( obj->data.atom );
if ( m < 1 || m > 12 )
{
fprintf( stderr, "%s: argument out of range: %d.\n", syntax, m );
return 1;
}
stack_push( stack, make_atom_from_string( months[ m - 1 ], -1 ));
}
return 0;
}
int do_negate( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
int i;
struct object *car;
car = stack_pop( stack );
i = number( car->data.atom );
stack_push( stack, make_atom_from_number( -i ));
}
return 0;
}
int do_getpid( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ) )
return 1;
stack_push( stack, make_atom_from_number( ( int )getpid() ) );
return 0;
}
int do_getppid( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
stack_push( stack, make_atom_from_number( ( int )getppid() ));
return 0;
}
int do_setpgid( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( setpgid( ( pid_t )number( car1->data.atom ), ( pid_t )number( car2->data.atom )) < 0 )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_getpgrp( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
stack_push( stack, make_atom_from_number( getpgrp() ));
return 0;
}
int do_tcgetpgrp( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
{
pid_t pid;
if ( isatty( 0 ) == 0 )
stack_push( stack, make_atom_from_number( 0 ));
else
{
pid = tcgetpgrp( 0 );
if ( pid < 0 )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else
stack_push( stack, make_atom_from_number( pid ));
}
}
return 0;
}
int do_tcsetpgrp( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
if ( isatty( 0 ) == 0 )
stack_push( stack, make_atom_from_number( 0 ));
else
{
if ( tcsetpgrp( 0, ( pid_t )number( car->data.atom ) ) < 0 )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ) );
else
stack_push( stack, make_atom_from_number( 1 ));
}
}
return 0;
}
int do_kill( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( kill( ( pid_t )number( car1->data.atom ), number( car2->data.atom )) < 0 )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ) );
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_killpg( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car1, *car2;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( killpg( ( pid_t )number( car1->data.atom ), number( car2->data.atom )) < 0 )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ) );
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_fork( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
stack_push( stack, make_atom_from_number( fork() ));
return 0;
}
int pipe_fork( char *syntax, int wrt )
{
int fd[ 2 ], pid, flag;
if ( pipe( &fd[ 0 ] ) < 0 )
{
fprintf( stderr, "%s: pipe: %s.\n", syntax, strerror( errno ));
return -1;
}
switch(( pid = fork() ))
{
case -1:
close( fd[ 0 ] );
close( fd[ 1 ] );
fprintf( stderr, "%s: fork: %s.\n", syntax, strerror( errno ));
return -2;
case 0:
if (( dup2( fd[ 1 ], !wrt )) < 0 )
{
fprintf( stderr, "%s (child): dup2: %s.\n", syntax, strerror( errno ));
_exit( 1 );
}
close( fd[ 0 ] );
close( fd[ 1 ] );
return 0;
default:
close( fd[ 1 ] );
if (( flag = dup( wrt )) < 0 )
{
close( fd[ 0 ] );
fprintf( stderr, "%s: dup: %s.\n", syntax, strerror( errno ));
return -1;
}
stack_push( descriptors[ wrt ], ( void *)flag );
if ( wrt )
fclose(( wrt == 1 ? stdout : stderr ));
if ( dup2( fd[ 0 ], wrt ) < 0 )
{
close( fd[ 0 ] );
close( ( int )stack_pop( descriptors[ wrt ] ));
fprintf( stderr, "%s: dup2: %s.\n", syntax, strerror( errno ));
return -1;
}
close( fd[ 0 ] );
if ( wrt == 1 )
{
stdout = fdopen( wrt, "w" );
if ( stdout == NULL )
{
fprintf( stderr, "%s: fdopen: %s.\n", syntax, strerror( errno ));
return -1;
}
}
else if ( wrt == 2 )
{
stderr = fdopen( wrt, "w" );
if ( stderr == NULL )
{
fprintf( stdout, "%s: fdopen: %s.\n", syntax, strerror( errno ));
return -1;
}
}
}
return pid;
}
int do_forkpipe( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
int i;
struct object *car;
car = stack_pop( stack );
i = number( car->data.atom );
if ( i < 0 || i > 2 )
{
fprintf( stderr, "%s: descriptor argument out of range: %d\n", syntax, i );
return 1;
}
if (( i = pipe_fork( syntax, i )) == -1 )
return 1;
stack_push( stack, make_atom_from_number( i ));
}
return 0;
}
int do_wait( char *syntax, struct object *args )
{
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, 0 );
return 1;
}
if ( args->next )
{
if ( args->next->next )
{
print_err( ERR_MORE_ARGS, syntax, 2, 0 );
return 1;
}
}
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, 0 );
return 1;
}
if ( args->next )
{
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, 0 );
return 1;
}
}
{
int status;
pid_t pid, i, opt;
struct object *obj, *car1, *car2;
car2 = ( args->next == NULL ? NULL : stack_pop( stack ));
car1 = stack_pop( stack );
if ( islist( car1->flags ) || numberp( car1->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_FIXNUM );
return 1;
}
i = number( car1->data.atom );
opt = 1;
if ( car2 == NULL ||
(( islist( car2->flags ) == 1 && car2->data.head == NULL ) ||
( islist( car2->flags ) == 0 && ( car2->data.atom == NULL ||
car2->data.atom == empty->data.atom ))))
opt = 0;
opt = ( opt ? ( WUNTRACED | WNOHANG ) : WUNTRACED );
if (( pid = waitpid( i, &status, opt )) < 0 )
{
if ( errno != ECHILD )
{
fprintf( stderr, "%s: %s.\n", syntax, strerror( errno ));
return 1;
}
}
obj = make_object();
stack_push( stack, obj );
setlist( obj->flags );
obj->data.head = make_atom_from_number( pid );
if ( pid == child_pid )
child_pid = -1;
if ( pid <= 0 )
{
obj->data.head->next = make_atom_from_symbol( "ECHILD" );
}
else if ( WIFEXITED( status ))
{
obj->data.head->next = make_atom_from_symbol( "EXITED" );
obj->data.head->next->next = make_atom_from_number( WEXITSTATUS( status ) );
}
else if ( WIFSTOPPED( status ))
{
obj->data.head->next = make_atom_from_symbol( "STOPPED" );
obj->data.head->next->next = make_atom_from_number( WSTOPSIG( status ));
}
else if ( WIFSIGNALED( status ))
{
obj->data.head->next = make_atom_from_symbol( "KILLED" );
obj->data.head->next->next = make_atom_from_number( WTERMSIG( status ));
}
}
return 0;
}
int do_zombies( char *syntax, struct object *args )
{
stack_push( stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
zombies = 1;
return 0;
}
int do_nozombies( char *syntax, struct object *args )
{
stack_push( stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
zombies = 0;
return 0;
}
int do_glob( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car, *result, **ptr;
glob_t globby;
char **path;
int i;
car = stack_pop( stack );
if ( glob( car->data.atom->data.string->string,
GLOB_NOSORT | GLOB_MARK | GLOB_BRACE | GLOB_NOCHECK | GLOB_TILDE,
NULL, &globby ) )
{
fprintf( stderr, "%s: %s.\n", syntax, strerror( errno ));
return 1;
}
result = make_object();
setlist( result->flags );
stack_push( stack, result );
for( path = globby.gl_pathv,
ptr = &result->data.head,
i = globby.gl_matchc;
i;
--i, ++path, ptr = &( *ptr )->next )
*ptr = make_atom_from_string( *path, -1 );
globfree( &globby );
}
return 0;
}
int dup_std( char *syntax, int std )
{
int fd;
FILE *file;
if (( fd = dup( std )) < 0 )
{
fprintf( stderr, "%s: dup: %s.\n", syntax, strerror( errno ));
return -1;
}
stack_push( descriptors[ std ], ( void *)fd );
fclose( ( std == 2 ? stderr : stdout ) );
if ( std == 2 )
stderr = NULL;
else
stdout = NULL;
if ( dup2( ( std == 2 ? 1 : 2 ), std ) < 0 )
{
resume( syntax, std );
fprintf( stderr, "%s: dup2: %s.\n", syntax, strerror( errno ));
return 1;
}
file = fdopen( std, "w" );
if ( file == NULL )
{
resume( syntax, std );
fprintf( stdout, "%s: fdopen: %s.\n", syntax, strerror( errno ));
return 1;
}
if ( std == 2 )
stderr = file;
else
stdout = file;
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_stderr2stdout( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
return dup_std( syntax, 2 );
}
int do_stdout2stderr( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
return dup_std( syntax, 1 );
}
int nth( char *syntax, struct object *list, int i, int cdr )
{
struct object *ptr, *obj;
if ( list->data.head == NULL )
{
stack_push( stack, list );
return 0;
}
if ( i < 0 )
{
fprintf( stderr, "%s: index must be >= 0: %d.\n", syntax, i );
return 1;
}
if ( !i )
stack_push( stack, ( cdr ? list : list->data.head ));
else
{
for( ptr = list->data.head;
( ptr != NULL && i );
--i, ptr = ptr->next )
;
if ( i || ptr == NULL )
{
obj = make_object();
setlist( obj->flags );
stack_push( stack, obj );
return 0;
}
if ( cdr )
{
obj = make_object();
setlist( obj->flags );
obj->data.head = ptr;
stack_push( stack, obj );
}
else
stack_push( stack, ptr );
}
return 0;
}
int do_nth( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_LIST );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
int i;
struct object *car1, *car2;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
i = number( car2->data.atom );
return nth( syntax, car1, i, 0 );
}
}
int do_nthcdr( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_LIST );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
{
int i;
struct object *car1, *car2;
car2 = stack_pop( stack );
car1 = stack_pop( stack );
i = number( car2->data.atom );
return nth( syntax, car1, i, 1 );
}
}
int do_reset_history( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
while( history->used )
free( stack_pop( history ));
history_ptr = 0;
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_zombiesp( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
stack_push( stack, make_atom_from_number( zombies ));
return 0;
}
int do_dec2hex( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *obj;
char buffer[ 64 ];
obj = stack_pop( stack );
snprintf( buffer, sizeof( buffer ), "%X", number( obj->data.atom ));
stack_push( stack, make_atom_from_string( buffer, -1 ) );
}
return 0;
}
int do_hex2dec( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *obj;
int d, s;
char *ptr;
obj = stack_pop( stack );
d = 0;
s = 1;
for( ptr = obj->data.atom->data.string->string +
obj->data.atom->data.string->length - 1;
ptr >= obj->data.atom->data.string->string;
--ptr )
if ( ! isxdigit( *ptr ))
{
fprintf( stderr, "%s: non-hex digit(s) in string: %s.\n", syntax, obj->data.atom->data.string->string );
return 1;
}
else
{
switch( *ptr )
{
case 'a':
case 'A':
d += s * 10;
break;
case 'b':
case 'B':
d += s * 11;
break;
case 'c':
case 'C':
d += s * 12;
break;
case 'd':
case 'D':
d += s * 13;
break;
case 'e':
case 'E':
d += s * 14;
break;
case 'f':
case 'F':
d += s * 15;
break;
default:
d += s * ( *ptr - 48 );
}
s *= 16;
}
stack_push( stack, make_atom_from_number( d ));
}
return 0;
}
int do_listen( char *syntax, struct object *args )
{
struct object *car1, *car2;
struct sockaddr_in serv_addr;
int fd, one = 1;
if ( args == NULL )
{
print_err( ERR_MISSING_ARGS, syntax, 0, 0 );
return 1;
}
if ( args->next != NULL )
{
car2 = args->next;
if ( args->next->next != NULL )
{
print_err( ERR_MORE_ARGS, syntax, 2, 0 );
return 1;
}
}
else
car2 = NULL;
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 1, 0 );
return 1;
}
if ( car2 != NULL )
{
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
print_err( ERR_EVAL, syntax, 2, 0 );
return 1;
}
car2 = stack_pop( stack );
}
car1 = stack_pop( stack );
if ( islist( car1->flags ) || numberp( car1->flags ) == 0 )
{
print_err( ERR_ARG_TYPE, syntax, 1, ERR_FIXNUM );
return 1;
}
if ( car2 != NULL &&
( islist( car2->flags ) || numberp( car2->flags ) ||
type( car2->data.atom->flags ) != ATOM_STRING ))
{
print_err( ERR_ARG_TYPE, syntax, 2, ERR_STRING );
return 1;
}
if ( serv_fd >= 0 )
{
stack_push( stack, make_atom_from_string( "already listening", -1 ));
return 0;
}
fd = socket( PF_INET, SOCK_STREAM, 0 );
if ( fd == -1 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof( one ));
bzero( &serv_addr, sizeof( serv_addr ));
serv_addr.sin_family = AF_INET;
if ( car2 == NULL )
serv_addr.sin_addr.s_addr = htonl( INADDR_ANY );
else
{
int result;
result = inet_aton( car2->data.atom->data.string->string,
( struct in_addr *)&serv_addr.sin_addr.s_addr );
if ( !result )
{
stack_push( stack, make_atom_from_string( "badly-formed address string", -1 ));
return 0;
}
else if ( result < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
}
serv_addr.sin_port = htons( number( car1->data.atom ));
if ( bind( fd, ( struct sockaddr *)&serv_addr, sizeof( serv_addr )) < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
if ( listen( fd, 30 ) < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
serv_fd = fd;
stack_push( stack, make_atom_from_number( ntohs( serv_addr.sin_port )));
return 0;
}
int do_accept( char *syntax, struct object *args )
{
struct sockaddr_in client_addr;
int dupin, dupout, fd;
socklen_t client_len;
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( serv_fd < 0 )
{
stack_push( stack, make_atom_from_string( "\"listen\" has not been invoked", -1 ));
return 0;
}
client_len = sizeof( client_addr );
AGAIN:
if (( fd = accept( serv_fd, ( struct sockaddr *)&client_addr, &client_len )) < 0 )
{
if ( errno == EAGAIN || errno == EINTR )
goto AGAIN;
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
close( serv_fd );
serv_fd = -1;
return 0;
}
if (( dupin = dup( 0 )) < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
if (( dupout = dup( 1 )) < 0 )
{
close( dupin );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( descriptors[ 0 ], ( struct atom *)dupin );
stack_push( descriptors[ 1 ], ( struct atom *)dupout );
fclose( stdout );
stdout = NULL;
if ( dup2( fd, 0 ) < 0 )
{
close( fd );
resume( syntax, 0 );
resume( syntax, 1 );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
if ( dup2( fd, 1 ) < 0 )
{
close( fd );
resume( syntax, 0 );
resume( syntax, 1 );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
close( fd );
stdout = fdopen( 1, "w" );
if ( stdout == NULL )
{
resume( syntax, 0 );
resume( syntax, 1 );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_daemonize( char *syntax, struct object *args )
{
struct object *car;
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 0;
car = stack_pop( stack );
/*
* Close any open full-duplex connection.
*/
if ( child_fd >= 0 )
{
do_child_close( syntax, NULL );
stack_pop( stack );
}
/*
* Close shadowed open descriptors.
*/
close_descriptors();
/*
* Close the standard descriptors now that all
* redirections have been undone.
*/
fclose( stdout );
fclose( stderr );
close( 0 );
/*
* Reopen the standard streams on /dev/null.
*/
stdin = fopen( "/dev/null", "r" );
stdout = fopen( "/dev/null", "w" );
stderr = fopen( "/dev/null", "w" );
syslog_name = str_dup( car->data.atom->data.string->string,
car->data.atom->data.string->length );
openlog( syslog_name, LOG_PID, LOG_DAEMON );
if ( stdin == NULL || stdout == NULL || stderr == NULL )
{
syslog( LOG_CRIT, "Cannot open one or more of the standard streams onto /dev/null." );
exit( 1 );
}
/*
* Fork and led the parent die, continuing as child so we are not
* a process group leader. This is necessary for the call to setsid().
*/
switch( fork() )
{
case -1:
syslog( LOG_CRIT, "Cannot fork." );
exit( 1 );
case 0:
break;
default:
exit( 0 );
}
do_block( syntax, NULL );
stack_pop( stack );
if ( setsid() < 0 )
{
syslog( LOG_CRIT, "setsid() failed." );
exit( 1 );
}
umask( 0 );
isdaemon = 1;
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_syslog( char *syntax, struct object *args )
{
struct object *car1, *car2;
if ( args == NULL )
{
syslog( LOG_CRIT, "%s: missing arguments.\n", syntax );
exit( 1 );
}
if ( args->next == NULL )
{
syslog( LOG_CRIT, "%s: missing argument 2.\n", syntax );
exit( 1 );
}
if ( args->next->next != NULL )
{
syslog( LOG_CRIT, "%s: called with more than 2 arguments.\n", syntax );
exit( 1 );
}
if ( !isdaemon )
{
stack_push( stack, make_atom_from_string( "\"daemonize\" has not been invoked", -1 ));
return 0;
}
stack_push( stack, args );
if ( evaluate() )
{
if ( !stop )
syslog( LOG_CRIT, "%s: evaluation of argument 1 failed.\n", syntax );
exit( 1 );
}
stack_push( stack, args->next );
if ( evaluate() )
{
if ( !stop )
syslog( LOG_CRIT, "%s: evaluation of argument 2 failed.\n", syntax );
exit( 1 );
}
car2 = stack_pop( stack );
car1 = stack_pop( stack );
if ( islist( car1->flags ) || numberp( car1->flags ) ||
type( car1->data.atom->flags ) != ATOM_SYMBOL )
{
syslog( LOG_CRIT, "%s: argument 1 did not evaluate to a symbol.\n", syntax );
exit( 1 );
}
if ( islist( car2->flags ) || numberp( car2->flags ) ||
type( car2->data.atom->flags ) != ATOM_STRING )
{
syslog( LOG_CRIT, "%s: argument 2 did not evaluate to a string.\n", syntax );
exit( 1 );
}
{
char *ptr;
struct string *msg;
int level;
if( !strcmp( car1->data.atom->syntax, "ALERT" ))
level = LOG_ALERT;
else if ( !strcmp( car1->data.atom->syntax, "CRITICAL" ))
level = LOG_CRIT;
else if ( !strcmp( car1->data.atom->syntax, "ERROR" ))
level = LOG_ERR;
else if ( !strcmp( car1->data.atom->syntax, "WARNING" ))
level = LOG_WARNING;
else if ( !strcmp( car1->data.atom->syntax, "NOTICE" ))
level = LOG_NOTICE;
else if ( !strcmp( car1->data.atom->syntax, "INFO" ))
level = LOG_INFO;
else if ( !strcmp( car1->data.atom->syntax, "DEBUG" ))
level = LOG_DEBUG;
else
{
syslog( LOG_CRIT, "%s: Unrecognized level: %s", syntax, car1->data.atom->syntax );
return 1;
}
msg = make_string();
for( ptr = car2->data.atom->data.string->string; *ptr; ++ptr )
{
if ( *ptr == '%' )
string_append( msg, *ptr );
string_append( msg, *ptr );
}
syslog( level, msg->str );
string_free( msg );
}
return 0;
}
int do_stop_listening( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( serv_fd >= 0 )
{
close( serv_fd );
serv_fd = -1;
stack_push( stack, make_atom_from_number( 1 ));
}
else
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
int do_base64_encode( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
unsigned int len, pad, i;
char *ptr, buff[ 3 ], *trailer;
struct string *s;
static char *encs = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
car = stack_pop( stack );
len = car->data.atom->data.string->length;
if ( !len )
{
stack_push( stack, empty );
return 0;
}
s = make_string();
string_append( s, '"' );
pad = len % 3;
ptr = car->data.atom->data.string->string;
if ( len > 2 )
{
len -= pad;
for( i = 0; i < len; i += 3 )
{
buff[ 0 ] = *ptr++;
buff[ 1 ] = *ptr++;
buff[ 2 ] = *ptr++;
string_append( s, encs[ ( buff[ 0 ] & 0xfc ) >> 2 ] );
string_append( s, encs[ (( buff[ 0 ] & 0x03 ) << 4 ) + (( buff[ 1 ] & 0xf0 ) >> 4 ) ] );
string_append( s, encs[ (( buff[ 1 ] & 0x0f ) << 2 ) + (( buff[ 2 ] & 0xc0 ) >> 6 ) ] );
string_append( s, encs[ buff[ 2 ] & 0x3f ] );
}
}
else
pad = len;
if ( pad )
{
buff[ 0 ] = *ptr++;
string_append( s, encs[ ( buff[ 0 ] & 0xfc ) >> 2 ] );
if ( --pad )
{
trailer = "=";
buff[ 1 ] = *ptr;
string_append( s, encs[ (( buff[ 0 ] & 0x03 ) << 4 ) + (( buff[ 1 ] & 0xf0 ) >> 4 ) ] );
string_append( s, encs[ (( buff[ 1 ] & 0x0f ) << 2 ) ] );
}
else
{
trailer = "==";
string_append( s, encs[ (( buff[ 0 ] & 0x03 ) << 4 ) ] );
}
for( ptr = trailer; *ptr; ++ptr )
string_append( s, *ptr );
}
stack_push( stack, make_atom_directly_from_string( s->str, s->used ));
free( s );
}
return 0;
}
int do_base64_decode( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
unsigned int i, pad;
char buff[ 4 ], *ptr;
struct string *s;
car = stack_pop( stack );
if ( car->data.atom->data.string->length % 4 )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
s = make_string();
string_append( s, '"' );
for( ptr = car->data.atom->data.string->string; *ptr; )
{
pad = 0;
for( i = 0; i < 4; ++i, ++ptr )
{
if ( *ptr >= 'A' && *ptr <= 'Z' )
buff[ i ] = *ptr - 65;
else if ( *ptr >= 'a' && *ptr <= 'z' )
buff[ i ] = *ptr - 97 + 26;
else if ( *ptr >= '0' && *ptr <= '9' )
buff[ i ] = *ptr - 48 + 52;
else if ( *ptr == '+' )
buff[ i ] = 62;
else if ( *ptr == '/' )
buff[ i ] = 63;
else if ( *ptr == '=' )
{
buff[ i ] = 0;
++pad;
}
else
{
string_free( s );
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
}
buff[ 0 ] <<= 2;
buff[ 0 ] += ( buff[ 1 ] & 0x30 ) >> 4;
buff[ 1 ] <<= 4;
buff[ 1 ] += ( buff[ 2 ] & 0x3c ) >> 2;
buff[ 2 ] <<= 6;
buff[ 2 ] += buff[ 3 ];
pad = 3 - pad;
for( i = 0; i < pad; ++i )
string_append( s, buff[ i ] );
}
stack_push( stack, make_atom_directly_from_string( s->str, s->used ));
free( s );
}
return 0;
}
int do_eval_string( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
int i;
/*
* Leave the string object on the stack so that it will be found
* during garbage collection, and left alone.
*/
car = *stack->top;
i = stack->used;
stack_push( string_stack, ( void *)car->data.atom->data.string->string );
--string_counter;
for( ; ; )
{
int depth;
depth = parse( string_counter );
if ( depth > 0 )
break;
else if ( depth < 0 )
fprintf( stderr, "%d extra ')'\n", -depth );
if ( evaluate() )
break;
car = stack_pop( stack );
}
while( input_stack->used )
stack_pop( input_stack );
/*
* Remove the argument string.
*/
stack_pop( stack );
get_token( 0, -1 );
++string_counter;
stack_push( stack, car );
}
return 0;
}
int do_flush_stdout( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
fflush( stdout );
stack_push( stack, make_atom_from_number( 1 ));
return 0;
}
int do_getpeername( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( serv_fd < 0 )
{
fprintf( stderr, "%s: \"listen\" has not been invoked.\n", syntax );
return 1;
}
{
struct sockaddr_in addr;
socklen_t len;
char address[ 16 ];
len = sizeof( struct sockaddr_in );
if ( getpeername( 0, ( struct sockaddr *)&addr, &len ) < 0 )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
if ( inet_ntop( AF_INET, &addr.sin_addr, address, sizeof( address )) == NULL )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
stack_push( stack, make_atom_from_string( address, -1 ));
}
return 0;
}
int do_temporary( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
{
char filename[] = "/tmp/mungerXXXXXXXXXX";
int fd, dupout;
if (( fd = mkstemp( filename )) < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
if (( dupout = dup( 1 )) < 0 )
{
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( descriptors[ 1 ], ( struct atom *)dupout );
fclose( stdout );
stdout = NULL;
if ( dup2( fd, 1 ) < 0 )
{
close( fd );
resume( syntax, 1 );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
close( fd );
stdout = fdopen( 1, "w" );
if ( stdout == NULL )
{
resume( syntax, 1 );
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
return 0;
}
stack_push( stack, make_atom_from_string( filename, -1 ));
}
return 0;
}
int get_token_from_buffer( char *syntax, int buff )
{
static char *ptr = NULL, *orig = NULL;
static int line = 0;
static int escape = 0;
int type, result;
if ( buff < 0 )
{
if ( orig != NULL )
free( orig );
ptr = orig = NULL;
line = 0;
return 0;
}
type = -1;
string_truncate( token );
for( ; ; )
{
if ( ptr == NULL || *ptr == 0 )
{
++line;
if ( orig != NULL )
{
free( orig );
ptr = orig = NULL;
}
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if (( result = (( DB *)buffer_stack->values[ buff ] )->seq(
( DB *)buffer_stack->values[ buff ], &dbt_key, &dbt_value, R_LAST )) == -1 )
{
fprintf( stderr, "%s: db->seq: %s.\n", syntax, strerror( errno ));
return TOK_END;
}
else if ( result == 1 || line > ( int )dbt_key.data )
{
line = 0;
if ( type >= 0 )
return type;
return ( type = TOK_END );
}
else
{
key_data = line;
dbt_key.data = &key_data;
dbt_key.size = sizeof( recno_t );
if (( result = (( DB *)buffer_stack->values[ buff ] )->get(
( DB *)buffer_stack->values[ buff ], &dbt_key, &dbt_value, 0 )) < 0 )
{
fprintf( stderr, "%s: db->get: %s.\n", syntax, strerror( errno ));
line = 0;
return TOK_END;
}
else if ( result == 1 )
{
line = 0;
return TOK_END;
}
ptr = orig = str_dup( dbt_value.data, dbt_value.size );
}
}
for( ; *ptr; )
{
if ( type == TOK_COMMENT )
{
if ( *ptr == '\n' || *ptr == '\r' )
{
string_truncate( token );
type = -1;
}
++ptr;
continue;
}
if ( *ptr == '\\' )
{
if ( type == TOK_STRING )
{
if ( !( escape ^= 1 ) )
string_chop( token );
}
else
{
++ptr;
continue;
}
}
else if ( *ptr != '"' )
escape = 0;
if ( *ptr == ';' || *ptr == '#' )
{
if ( type < 0 )
type = TOK_COMMENT;
else if ( type != TOK_STRING )
return type;
string_append( token, *ptr++ );
}
else if ( *ptr == '(' || *ptr == ')' )
{
if ( type >= 0 )
{
if ( type == TOK_STRING )
{
string_append( token, *ptr++ );
continue;
}
return type;
}
type = ( *ptr == '(' ? TOK_OPEN : TOK_CLOSE );
string_append( token, *ptr++ );
return type;
}
else if ( *ptr == '"' )
{
if ( type < 0 )
{
type = TOK_STRING;
string_append( token, *ptr++ );
}
else if ( type != TOK_STRING )
return type;
else
{
if ( escape )
string_chop( token );
string_append( token, *ptr++ );
if ( !escape )
return type;
escape = 0;
}
}
else if (( *ptr >= 'A' && *ptr <= 'Z' ) ||
( *ptr >= 'a' && *ptr <= 'z' ) || *ptr == '_' )
{
if ( type == -1 )
type = TOK_SYMBOL;
else if ( type != TOK_STRING && type != TOK_SYMBOL )
return type;
string_append( token, *ptr++ );
}
else if ( *ptr >= '0' && *ptr <= '9' )
{
if ( type == -1 || type == TOK_MINUS )
type = TOK_FIXNUM ;
else if ( type != TOK_STRING && type != TOK_SYMBOL &&
type != TOK_FIXNUM )
return type;
string_append( token, *ptr++ );
}
else if ( !isspace( *ptr ))
{
if ( type == -1 )
{
if ( *ptr == '\'' )
type = TOK_QUOTE;
else if ( *ptr == '-' )
type = TOK_MINUS;
else
type = TOK_SPECIAL;
}
else if ( type != TOK_STRING &&
type != TOK_SPECIAL )
return type;
string_append( token, *ptr++ );
}
else
{
if ( type >= 0 )
{
if ( type != TOK_STRING )
return type;
else if ( *ptr == '\r' )
{
if ( isatty( 0 ))
string_append( token, '\n' );
else
string_append( token, *ptr++ );
}
else
string_append( token, *ptr++ );
}
else
++ptr;
}
}
}
return type;
}
int parse_buffer( char *syntax, int buff )
{
int depth = 0;
for( ; ; )
{
int type;
type = get_token_from_buffer( syntax, buff );
if ( type == TOK_END )
return 1;
depth = process_token( type, depth );
if ( depth <= 0 )
break;
}
return depth;
}
int do_eval_buffer( char *syntax, struct object *args )
{
static int running = 0;
stack_push( arg_stack, ( void *)0 );
if ( check_args( syntax, args ))
return 1;
if ( running )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
running = 1;
if ( do_lastline( syntax, NULL ))
return 1;
{
struct object *car;
int last, count, i;
car = stack_pop( stack );
last = number( car->data.atom );
if ( !last )
{
stack_push( stack, make_atom_from_number( 0 ));
return 0;
}
for( i = 0; i < buffer_stack->used; ++i )
if ( buffer == buffer_stack->values[ i ] )
break;
for( count = 1; ; ++count )
{
int depth;
depth = parse_buffer( syntax, i );
if ( depth > 0 )
break;
else if ( depth < 0 )
fprintf( stderr, "%d extra ')'\n", -depth );
if ( evaluate() )
{
if ( !stop )
fprintf( stderr, "%s: evaluation of expression %d in buffer %d "
"failed.\n", syntax, count, i );
get_token_from_buffer( syntax, -1 );
running = 0;
return 1;
}
car = stack_pop( stack );
}
get_token_from_buffer( syntax, -1 );
running = 0;
stack_push( stack, car );
}
return 0;
}
int do_chroot( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
car = stack_pop( stack );
if ( chroot( car->data.atom->data.string->string ) < 0 )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_setgid( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
struct group *group;
car = stack_pop( stack );
if (( group = getgrnam( car->data.atom->data.string->string )) == NULL )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else if ( setgid( group->gr_gid ) < 0 )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_setegid( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_STRING );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
struct group *group;
car = stack_pop( stack );
if (( group = getgrnam( car->data.atom->data.string->string )) == NULL )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else if ( setegid( group->gr_gid ) < 0 )
stack_push( stack, make_atom_from_string( strerror( errno ), -1 ));
else
stack_push( stack, make_atom_from_number( 1 ));
}
return 0;
}
int do_getline_ub( char *syntax, struct object *args )
{
if ( args != NULL )
{
if ( args->next == NULL )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
}
else if ( args->next->next == NULL )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)2 );
if ( check_args( syntax, args ))
return 1;
}
else
{
print_err( ERR_MORE_ARGS, syntax, 0, -1 );
return 1;
}
}
{
int timeout, r, limit, count;
char c;
struct string *s;
struct itimerval value;
timeout = 0;
limit = INT_MAX;
if ( args != NULL )
{
struct object *ptr;
if ( args->next != NULL )
{
ptr = stack_pop( stack );
limit = number( ptr->data.atom );
if ( limit <= 0 )
{
fprintf( stderr, "%s: limit value <= 0: %d.\n",
syntax, limit );
return 1;
}
}
ptr = stack_pop( stack );
timeout = number( ptr->data.atom );
if ( timeout < 0 )
{
fprintf( stderr, "%s: timeout value < 0: %d.\n",
syntax, timeout );
return 1;
}
}
s = make_string();
string_append( s, '"' );
count = 0;
AGAIN:
for( ; ; )
{
if ( timeout )
{
value.it_interval.tv_sec = 0;
value.it_interval.tv_usec = 0;
value.it_value.tv_sec = timeout;
value.it_value.tv_usec = 0;
setitimer( ITIMER_REAL, &value, NULL );
}
if (( r = read( 0, &c, 1 )) <= 0 )
break;
string_append( s, c );
if ( c == 10 || ++count == limit )
break;
}
if ( timeout )
{
value.it_value.tv_sec = 0;
value.it_value.tv_usec = 0;
setitimer( ITIMER_REAL, &value, NULL );
}
if ( r < 0 )
{
if ( sigalrm )
{
/*
* Will always be empty string when reading from a terminal in
* canonical mode because we won't get any data until a
* carriage return is entered.
*/
stack_push( stack, make_atom_directly_from_string( s->str, s->used ));
sigalrm = 0;
free( s );
}
else if ( errno == EINTR || errno == EAGAIN )
goto AGAIN;
else
{
stack_push( stack, make_atom_from_number( 0 ));
string_free( s );
}
}
else if ( ! r )
{
if ( s->used > 1 )
{
stack_push( stack, make_atom_directly_from_string( s->str, s->used ));
free( s );
}
else
{
string_free( s );
stack_push( stack, make_atom_from_number( 0 ));
}
}
else
{
stack_push( stack, make_atom_directly_from_string( s->str, s->used ));
free( s );
}
}
return 0;
}
int do_isatty( char *syntax, struct object *args )
{
stack_push( arg_stack, ( void *)ERR_FIXNUM );
stack_push( arg_stack, ( void *)1 );
if ( check_args( syntax, args ))
return 1;
{
struct object *car;
int n;
car = stack_pop( stack );
n = number( car->data.atom );
if ( n < 0 || n > 2 )
{
fprintf( stderr, "%s: descriptor out of range: %d.\n", syntax, n );
return 1;
}
stack_push( stack, make_atom_from_number( isatty( n )));
}
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1