1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
/*
* Copyright 1997 Thierry Bousch
* Licensed under the Gnu Public License, Version 2
*
* $Id: functions.c,v 1.2 1997/04/16 18:16:29 bousch Exp $
*
* Builtin and external functions
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "saml.h"
#include "saml-parse.h"
#include "samuel.h"
typedef struct builtin_function {
const char *name;
int (*fn)(mref_t result, int argc, mref_t *argv);
} BFN;
BFN bfns[] = {
{ "det", fn_determinant },
{ "getpid", fn_getpid },
{ "sqrt", fn_sqrt },
{ "variables", fn_variables },
{ 0, 0 }
};
#define FN_PREFIX "fn_"
int execute_function (const char* cmd, int nb_args)
{
char *command, *p, **argv;
int i, argc, fd[2], child, retval;
mref_t result = mref_new();
FILE *fp;
BFN *t;
for (t = bfns; t->name; t++)
if (strcmp(t->name,cmd) == 0) {
mref_t arglist[nb_args];
for (i = nb_args-1; i >= 0; i--)
arglist[i] = pop_mref();
retval = (*t->fn)(result, nb_args, arglist);
for (i = nb_args-1; i >= 0; i--)
mref_free(arglist[i]);
push_mref(result);
return retval;
}
/* Not a builtin function */
if (pipe(fd) < 0) {
perror("samuel: pipe");
retval = -1;
goto exit_fn;
}
if ((child = fork()) < 0) {
perror("fork");
retval = -1;
goto exit_fn;
}
if (child == 0) {
/*
* This is the child. We copy the command in writable space,
* compute the number of arguments (argc), and allocate
* space for the arguments (argv), and finally, exec.
*/
close(fd[0]);
if (dup2(fd[1],1) < 0)
perror("samuel: dup2");
command = alloca(strlen(cmd)+strlen(FN_PREFIX)+1);
if (strncmp(cmd, "induce ", 7) == 0) {
/* Magic. That's for subscripted literals */
strcpy(command, cmd);
} else {
/* Normal case, prepend "fn_" before the name */
strcpy(command, FN_PREFIX);
strcat(command, cmd);
}
argc = 1 + nb_args;
for (p = command; *p; p++)
if (*p == ' ') ++argc;
argv = alloca((argc+1)*sizeof(char*));
argv[0] = command;
argv[argc] = NULL;
argc = 1;
for (p = command; *p; p++)
if (*p == ' ') {
*p = '\0';
argv[argc++] = p+1;
}
/* Beware: the arguments are popped from last to first */
for (i = nb_args-1; i >= 0; i--) {
p = mref_string(pop_mref());
p = strcpy(alloca(strlen(p)+1), p);
argv[argc+i] = p;
}
execvp(command, argv);
perror("samuel: execvp");
_exit(127);
}
/* This is the parent process */
close(fd[1]);
if ((fp = fdopen(fd[0],"r")) == NULL) {
perror("samuel: fdopen");
retval = -1;
goto exit_fn;
}
saml_init_lexer_fd(fp);
retval = saml_parse(result, mr_model);
fclose(fp);
/* Wait for the child to terminate */
while (waitpid(child,NULL,0) < 0 && errno == EINTR)
;
exit_fn:
/* Update the stack */
while (nb_args--)
mref_free(pop_mref());
push_mref(result);
return retval;
}
/*
* Miscillaneous builtin functions
*/
int fn_determinant (mref_t result, int n2, mref_t *argv)
{
int i, j, n;
mref_t line, matrix;
/* Check that n2 is a square */
for (n = 0; n*n < n2; n++)
;
if (n*n != n2) {
fprintf(stderr, "fn_determinant: not square\n");
return 1;
}
line = mref_new();
matrix = mref_new();
mref_array(matrix, ST_MATRIX, n);
mref_array(line, ST_LINE, n);
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
mref_setitem(line, j, argv[n*i+j]);
mref_setitem(matrix, i, line);
}
mref_det(result, matrix);
mref_free(line);
mref_free(matrix);
return 0;
}
int fn_getpid (mref_t result, int argc, mref_t *argv)
{
char buffer[24];
sprintf(buffer, "%d", getpid());
mref_build(result, ST_INTEGER, buffer);
mref_promote(result, mr_model);
return 0;
}
int fn_sqrt (mref_t result, int argc, mref_t *argv)
{
if (argc != 1) {
fprintf(stderr, "Usage: fn_sqrt <number>\n");
return 1;
}
/* Convert to a string, and convert back to an integer */
mref_build(result, ST_INTEGER, mref_string(argv[0]));
if (mref_type(result) == ST_VOID) {
fprintf(stderr, "fn_sqrt: non-numeric argument\n");
return 1;
}
mref_sqrt(result, result);
if (mref_type(result) == ST_VOID) {
fprintf(stderr, "fn_sqrt: negative number\n");
return 1;
}
mref_promote(result, mr_model);
return 0;
}
|