/*1** stub main for testing FICL under userland2** $Id: testmain.c,v 1.13 2001/12/05 07:21:34 jsadler Exp $3*/4/*5** Copyright (c) 1997-2001 John Sadler ([email protected])6** All rights reserved.7**8** Get the latest Ficl release at http://ficl.sourceforge.net9**10** I am interested in hearing from anyone who uses ficl. If you have11** a problem, a success story, a defect, an enhancement request, or12** if you would like to contribute to the ficl release, please13** contact me by email at the address above.14**15** L I C E N S E and D I S C L A I M E R16**17** Redistribution and use in source and binary forms, with or without18** modification, are permitted provided that the following conditions19** are met:20** 1. Redistributions of source code must retain the above copyright21** notice, this list of conditions and the following disclaimer.22** 2. Redistributions in binary form must reproduce the above copyright23** notice, this list of conditions and the following disclaimer in the24** documentation and/or other materials provided with the distribution.25**26** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND27** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE28** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE29** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE30** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL31** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS32** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)33** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT34** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY35** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF36** SUCH DAMAGE.37*/383940#include <stdlib.h>41#include <stdio.h>42#include <string.h>43#include <time.h>44#include <sys/types.h>45#include <sys/stat.h>46#include <unistd.h>4748#include "ficl.h"4950/*51** Ficl interface to getcwd52** Prints the current working directory using the VM's53** textOut method...54*/55static void ficlGetCWD(FICL_VM *pVM)56{57char *cp;5859cp = getcwd(NULL, 80);60vmTextOut(pVM, cp, 1);61free(cp);62return;63}6465/*66** Ficl interface to chdir67** Gets a newline (or NULL) delimited string from the input68** and feeds it to chdir()69** Example:70** cd c:\tmp71*/72static void ficlChDir(FICL_VM *pVM)73{74FICL_STRING *pFS = (FICL_STRING *)pVM->pad;75vmGetString(pVM, pFS, '\n');76if (pFS->count > 0)77{78int err = chdir(pFS->text);79if (err)80{81vmTextOut(pVM, "Error: path not found", 1);82vmThrow(pVM, VM_QUIT);83}84}85else86{87vmTextOut(pVM, "Warning (chdir): nothing happened", 1);88}89return;90}9192/*93** Ficl interface to system (ANSI)94** Gets a newline (or NULL) delimited string from the input95** and feeds it to system()96** Example:97** system rm -rf /98** \ ouch!99*/100static void ficlSystem(FICL_VM *pVM)101{102FICL_STRING *pFS = (FICL_STRING *)pVM->pad;103104vmGetString(pVM, pFS, '\n');105if (pFS->count > 0)106{107int err = system(pFS->text);108if (err)109{110sprintf(pVM->pad, "System call returned %d", err);111vmTextOut(pVM, pVM->pad, 1);112vmThrow(pVM, VM_QUIT);113}114}115else116{117vmTextOut(pVM, "Warning (system): nothing happened", 1);118}119return;120}121122/*123** Ficl add-in to load a text file and execute it...124** Cheesy, but illustrative.125** Line oriented... filename is newline (or NULL) delimited.126** Example:127** load test.ficl128*/129#define nLINEBUF 256130static void ficlLoad(FICL_VM *pVM)131{132char cp[nLINEBUF];133char filename[nLINEBUF];134FICL_STRING *pFilename = (FICL_STRING *)filename;135int nLine = 0;136FILE *fp;137int result;138CELL id;139struct stat buf;140141142vmGetString(pVM, pFilename, '\n');143144if (pFilename->count <= 0)145{146vmTextOut(pVM, "Warning (load): nothing happened", 1);147return;148}149150/*151** get the file's size and make sure it exists152*/153result = stat( pFilename->text, &buf );154155if (result != 0)156{157vmTextOut(pVM, "Unable to stat file: ", 0);158vmTextOut(pVM, pFilename->text, 1);159vmThrow(pVM, VM_QUIT);160}161162fp = fopen(pFilename->text, "r");163if (!fp)164{165vmTextOut(pVM, "Unable to open file ", 0);166vmTextOut(pVM, pFilename->text, 1);167vmThrow(pVM, VM_QUIT);168}169170id = pVM->sourceID;171pVM->sourceID.p = (void *)fp;172173/* feed each line to ficlExec */174while (fgets(cp, nLINEBUF, fp))175{176int len = strlen(cp) - 1;177178nLine++;179if (len <= 0)180continue;181182result = ficlExecC(pVM, cp, len);183if (result != VM_QUIT && result != VM_USEREXIT && result != VM_OUTOFTEXT )184{185pVM->sourceID = id;186fclose(fp);187vmThrowErr(pVM, "Error loading file <%s> line %d", pFilename->text, nLine);188break;189}190}191/*192** Pass an empty line with SOURCE-ID == -1 to flush193** any pending REFILLs (as required by FILE wordset)194*/195pVM->sourceID.i = -1;196ficlExec(pVM, "");197198pVM->sourceID = id;199fclose(fp);200201/* handle "bye" in loaded files. --lch */202if (result == VM_USEREXIT)203vmThrow(pVM, VM_USEREXIT);204return;205}206207/*208** Dump a tab delimited file that summarizes the contents of the209** dictionary hash table by hashcode...210*/211static void spewHash(FICL_VM *pVM)212{213FICL_HASH *pHash = vmGetDict(pVM)->pForthWords;214FICL_WORD *pFW;215FILE *pOut;216unsigned i;217unsigned nHash = pHash->size;218219if (!vmGetWordToPad(pVM))220vmThrow(pVM, VM_OUTOFTEXT);221222pOut = fopen(pVM->pad, "w");223if (!pOut)224{225vmTextOut(pVM, "unable to open file", 1);226return;227}228229for (i=0; i < nHash; i++)230{231int n = 0;232233pFW = pHash->table[i];234while (pFW)235{236n++;237pFW = pFW->link;238}239240fprintf(pOut, "%d\t%d", i, n);241242pFW = pHash->table[i];243while (pFW)244{245fprintf(pOut, "\t%s", pFW->name);246pFW = pFW->link;247}248249fprintf(pOut, "\n");250}251252fclose(pOut);253return;254}255256static void ficlBreak(FICL_VM *pVM)257{258pVM->state = pVM->state;259return;260}261262static void ficlClock(FICL_VM *pVM)263{264clock_t now = clock();265stackPushUNS(pVM->pStack, (FICL_UNS)now);266return;267}268269static void clocksPerSec(FICL_VM *pVM)270{271stackPushUNS(pVM->pStack, CLOCKS_PER_SEC);272return;273}274275276static void execxt(FICL_VM *pVM)277{278FICL_WORD *pFW;279#if FICL_ROBUST > 1280vmCheckStack(pVM, 1, 0);281#endif282283pFW = stackPopPtr(pVM->pStack);284ficlExecXT(pVM, pFW);285286return;287}288289290void buildTestInterface(FICL_SYSTEM *pSys)291{292ficlBuild(pSys, "break", ficlBreak, FW_DEFAULT);293ficlBuild(pSys, "clock", ficlClock, FW_DEFAULT);294ficlBuild(pSys, "cd", ficlChDir, FW_DEFAULT);295ficlBuild(pSys, "execxt", execxt, FW_DEFAULT);296ficlBuild(pSys, "load", ficlLoad, FW_DEFAULT);297ficlBuild(pSys, "pwd", ficlGetCWD, FW_DEFAULT);298ficlBuild(pSys, "system", ficlSystem, FW_DEFAULT);299ficlBuild(pSys, "spewhash", spewHash, FW_DEFAULT);300ficlBuild(pSys, "clocks/sec",301clocksPerSec, FW_DEFAULT);302303return;304}305306307int main(int argc, char **argv)308{309char in[256];310FICL_VM *pVM;311FICL_SYSTEM *pSys;312313pSys = ficlInitSystem(10000);314buildTestInterface(pSys);315pVM = ficlNewVM(pSys);316317ficlEvaluate(pVM, ".ver .( " __DATE__ " ) cr quit");318319/*320** load file from cmd line...321*/322if (argc > 1)323{324sprintf(in, ".( loading %s ) cr load %s\n cr", argv[1], argv[1]);325ficlEvaluate(pVM, in);326}327328for (;;)329{330int ret;331if (fgets(in, sizeof(in) - 1, stdin) == NULL)332break;333ret = ficlExec(pVM, in);334if (ret == VM_USEREXIT)335{336ficlTermSystem(pSys);337break;338}339}340341return 0;342}343344345346