diff --git a/system/main.c b/apps/example1/main.c similarity index 100% rename from system/main.c rename to apps/example1/main.c diff --git a/apps/example_mutex/README b/apps/example_mutex/README new file mode 100644 index 0000000..e36c4cd --- /dev/null +++ b/apps/example_mutex/README @@ -0,0 +1,6 @@ + +This app needs the below modificationes into conf/Configuration file: + +#define NPROC 4 /* number of user processes */ +#define NSEM 6 /* number of semaphores */ + diff --git a/apps/example_mutex/main.c b/apps/example_mutex/main.c new file mode 100644 index 0000000..57c6782 --- /dev/null +++ b/apps/example_mutex/main.c @@ -0,0 +1,137 @@ +/* xsh_test.c - xsh_test */ + +#include +#include + +/* +void sndA(void); +void sndB(void); +*/ +// void prod2(sid32 consumed, sid32 produced, int a); +// void cons2(sid32 consumed, sid32 produced, int a); + +int32 n = 0; +int32 j = 0; + +//void cons2(sid32 consumed, sid32 produced, int a); +void cons2(int argc, char * argv[]); +void prod2(int argc, char * argv[]); + +void freem(void) +{ + int mask = disable(); + uint32 free_mem=0; + struct memblk *memptr; + /* Output Xinu memory layout */ + free_mem = 0; + for (memptr = memlist.mnext; memptr != NULL; + memptr = memptr->mnext) { + free_mem += memptr->mlength; + } + kprintf("\n\rFreeMEM:%d\n", free_mem); + restore(mask); +} + +/*------------------------------------------------------------------------ + * xhs_test + *------------------------------------------------------------------------ + */ +process main(void) +{ +// int32 a = roundmb(81); + +/* EEPROM TEST + char buf[6]; + char buf2[6]; + memset(buf, 0, 6); + memset(buf2, 0, 6); + buf[0] = 49; + buf[1] = 50; + printf("b=%s\n", buf); + write(EEPROM0, buf, 4); + buf[0] = 0; + buf[1] = 0; + read(EEPROM0, buf2, 4); + buf2[1] = 0; + printf("b=%s\n", buf2); + blink_avr(); + blink_avr(); + blink_avr(); + blink_avr(); + blink_avr(); + blink_avr(); + EN EEPROM TEST */ + + sid32 produced, consumed; + consumed = semcreate(0); + produced = semcreate(1); + printf ("prod=%d \n", produced); + printf ("consu=%d \n", consumed); + blink_avr(); + blink_avr(); + resume(create(cons2, 200, 20, "cons", 3, consumed, produced, 4)); + resume(create(prod2, 200, 20, "prod", 3, consumed, produced, 4)); + return 0; +} + +void prod2(int argc, char * argv[]) +{ + sid32 consumed, produced; + consumed = argv[0]; + produced = argv[1]; + int a = argv[2]; + int32 i; + + printf("argc=%d\n", argc); + printf("n1=%d\n", consumed); + printf("n2=%d\n", produced); + printf("n3=%d\n", a); + //for (i=1; i<=2000; i++) { + for (i=1; i<=100; i++) { +// printf("n3=%d\n", a); + wait(consumed); + j = j + 1; + //n++; + signal(produced); + } +} + +void cons2(int argc, char * argv[]) +//void cons2(sid32 consumed, sid32 produced, int a) +{ + int32 i; + + sid32 consumed, produced; + consumed = argv[0]; + produced = argv[1]; + //for (i=1; i<=2000; i++) { + for (i=1; i<=100; i++) { + wait(produced); + n = n + (j*2); + printf("n is %d \n", n); + signal(consumed); + } + +} +/* original test +process test(int nargs, char *args[]) +{ + resume(create(sndA, 64, 20, "proc1", 0)); + resume(create(sndB, 64, 20, "proc1", 0)); + + return 0; +} + +void sndA(void) +{ + while(1) + putc(CONSOLE, 'A'); +} + +void sndB(void) +{ + while(1) + putc(CONSOLE, 'B'); + +} +end of original test */ diff --git a/apps/shell/README b/apps/shell/README new file mode 100644 index 0000000..fc9b5b4 --- /dev/null +++ b/apps/shell/README @@ -0,0 +1,6 @@ + +This app needs the below modificationes into conf/Configuration file: + +#define NPROC 3 /* number of user processes */ +#define NSEM 2 /* number of semaphores */ + diff --git a/apps/shell/addargs.c b/apps/shell/addargs.c new file mode 100644 index 0000000..48580f6 --- /dev/null +++ b/apps/shell/addargs.c @@ -0,0 +1,119 @@ +/* addargs.c - addargs */ + +#include +#include "shprototypes.h" + +/*------------------------------------------------------------------------ + * addargs - Add local copy of argv-style arguments to the stack of + * a command process that has been created by the shell + *------------------------------------------------------------------------ + */ +status addargs( + pid32 pid, /* ID of process to use */ + int32 ntok, /* Count of arguments */ + int32 tok[], /* Index of tokens in tokbuf */ + int32 tlen, /* Length of data in tokbuf */ + char *tokbuf, /* Array of null-term. tokens */ + void *dummy /* Dummy argument that was */ + /* used at creation and must */ + /* be replaced by a pointer */ + /* to an argument vector */ + ) +{ + intmask mask; /* Saved interrupt mask */ + struct procent *prptr; /* Ptr to process' table entry */ + uint32 aloc; /* Argument location in process */ + /* stack as an integer */ + uint32 *argloc; /* Location in process's stack */ + /* to place args vector */ + char *argstr; /* Location in process's stack */ + /* to place arg strings */ + uint32 *search; /* pointer that searches for */ + /* dummy argument on stack */ + uint32 *aptr; /* Walks through args array */ + int32 i; /* Index into tok array */ + + mask = disable(); + + /* Check argument count and data length */ + + if ( (ntok <= 0) || (tlen < 0) ) { + // serial_put_char('M'); + restore(mask); + return SYSERR; + } + + prptr = &proctab[pid]; + + /* Compute lowest location in the process stack where the */ + /* args array will be stored followed by the argument */ + /* strings */ + +// aloc = (uint32) (prptr->prstkbase +// - prptr->prstklen + sizeof(uint32)); +// argloc = (uint32*) ((aloc + 3) & ~0x3); /* round multiple of 4 */ + + /* Compute the first location beyond args array for the strings */ +// +// argstr = (char *) (argloc + (ntok+1)); /* +1 for a null ptr */ + + /* Set each location in the args vector to be the address of */ + /* string area plus the offset of this argument */ + +// for (aptr=argloc, i=0; i < ntok; i++) { +// *aptr++ = (uint32) (argstr + tok[i]); +// } + + /* Add a null pointer to the args array */ + +// *aptr++ = (uint32)NULL; + + /* Copy the argument strings from tokbuf into process's stack */ + /* just beyond the args vector */ + +// memcpy(aptr, tokbuf, tlen); + + /* Find the second argument in process's stack */ + +// for (search = (uint32 *)prptr->prstkptr; +// search < (uint32 *)prptr->prstkbase; search++) { + + /* If found, replace with the address of the args vector*/ + +// if (*search == (uint32)dummy) { +// *search = (uint32)argloc; +// restore(mask); +// return OK; +// } +// } + + /* Argument value not found on the stack - report an error */ + + // serial_put_char('\n'); + +// for (fromarg=Shl.shtok ; nargs > 0 ; nargs--) { + for (i=0 ; i < ntok; i++) { + // prptr->parg[i+prptr->pargs] = (int)tok[i]; /******** change int parg[] TO void *parg[] in proc.h ******/ + // prptr->parg[i+prptr->pargs] = (void *)tok[i]; /******** change int parg[] TO void *parg[] in proc.h ******/ +// serial_put_char(48+i); +// serial_put_char(' '); +// serial_put_char(tokbuf[tok[i]]); +// serial_put_char(' '); + prptr->parg[i] = &tokbuf[tok[i]]; + + } +// *toarg = 0; + prptr->pargs = ntok; + prptr->parg[ntok] = 0; + +// RAFA prptr->pargs += ntok; +// RAFA prptr->parg[prptr->pargs] = 0; + /* machine/compiler dependent pass arguments to created process */ + prptr->pregs[24] = lobyte((unsigned)prptr->pargs); /*r24*/ + prptr->pregs[25] = hibyte((unsigned)prptr->pargs); + + + restore(mask); + return OK; +// return SYSERR; +} diff --git a/apps/shell/lexan.c b/apps/shell/lexan.c new file mode 100644 index 0000000..4e0cb8b --- /dev/null +++ b/apps/shell/lexan.c @@ -0,0 +1,148 @@ +/* lexan.c - lexan */ + +#include + +/*------------------------------------------------------------------------ + * lexan - Ad hoc lexical analyzer to divide command line into tokens + *------------------------------------------------------------------------ + */ + +int32 lexan ( + char *line, /* Input line terminated with */ + /* NEWLINE or NULLCH */ + int32 len, /* Length of the input line, */ + /* including NEWLINE */ + char *tokbuf, /* Buffer into which tokens are */ + /* stored with a null */ + /* following each token */ + int32 *tlen, /* Place to store number of */ + /* chars in tokbuf */ + int32 tok[], /* Array of pointers to the */ + /* start of each token */ + int32 toktyp[] /* Array that gives the type */ + /* of each token */ + ) +{ + char quote; /* Character for quoted string */ + uint32 ntok; /* Number of tokens found */ + char *p; /* Pointer that walks along the */ + /* input line */ + int32 tbindex; /* Index into tokbuf */ + char ch; /* Next char from input line */ + + /* Start at the beginning of the line with no tokens */ + + ntok = 0; + p = line; + tbindex = 0; + + /* While not yet at end of line, get next token */ + + while ( (*p != NULLCH) && (*p != SH_NEWLINE) ) { + + /* If too many tokens, return error */ + + if (ntok >= SHELL_MAXTOK) { + return SYSERR; + } + + /* Skip whitespace before token */ + + while ( (*p == SH_BLANK) || (*p == SH_TAB) ) { + p++; + } + + /* Stop parsing at end of line (or end of string) */ + + ch = *p; + if ( (ch==SH_NEWLINE) || (ch==NULLCH) ) { + *tlen = tbindex; + return ntok; + } + + /* Set next entry in tok array to be an index to the */ + /* current location in the token buffer */ + + tok[ntok] = tbindex; /* the start of the token */ + + /* Set the token type */ + + switch (ch) { + + case SH_AMPER: toktyp[ntok] = SH_TOK_AMPER; + tokbuf[tbindex++] = ch; + tokbuf[tbindex++] = NULLCH; + ntok++; + p++; + continue; + + case SH_LESS: toktyp[ntok] = SH_TOK_LESS; + tokbuf[tbindex++] = ch; + tokbuf[tbindex++] = NULLCH; + ntok++; + p++; + continue; + + case SH_GREATER: toktyp[ntok] = SH_TOK_GREATER; + tokbuf[tbindex++] = ch; + tokbuf[tbindex++] = NULLCH; + ntok++; + p++; + continue; + + default: toktyp[ntok] = SH_TOK_OTHER; + }; + + /* Handle quoted string (single or double quote) */ + + if ( (ch==SH_SQUOTE) || (ch==SH_DQUOTE) ) { + quote = ch; /* remember opening quote */ + + /* Copy quoted string to arg area */ + + p++; /* Move past starting quote */ + + while ( ((ch=*p++) != quote) && (ch != SH_NEWLINE) + && (ch != NULLCH) ) { + tokbuf[tbindex++] = ch; + } + if (ch != quote) { /* string missing end quote */ + return SYSERR; + } + + /* Finished string - count token and go on */ + + tokbuf[tbindex++] = NULLCH; /* terminate token */ + ntok++; /* count string as one token */ + continue; /* go to next token */ + } + + /* Handle a token other than a quoted string */ + + tokbuf[tbindex++] = ch; /* put first character in buffer*/ + p++; + + while ( ((ch = *p) != SH_NEWLINE) && (ch != NULLCH) + && (ch != SH_LESS) && (ch != SH_GREATER) + && (ch != SH_BLANK) && (ch != SH_TAB) + && (ch != SH_AMPER) && (ch != SH_SQUOTE) + && (ch != SH_DQUOTE) ) { + tokbuf[tbindex++] = ch; + p++; + } + + /* Report error if other token is appended */ + + if ( (ch == SH_SQUOTE) || (ch == SH_DQUOTE) + || (ch == SH_LESS) || (ch == SH_GREATER) ) { + return SYSERR; + } + + tokbuf[tbindex++] = NULLCH; /* terminate the token */ + + ntok++; /* count valid token */ + + } + *tlen = tbindex; + return ntok; +} diff --git a/apps/shell/main.c b/apps/shell/main.c new file mode 100644 index 0000000..229dbad --- /dev/null +++ b/apps/shell/main.c @@ -0,0 +1,331 @@ +/* main.c - main */ + +/* shell.c - shell */ + + +#include +//#include +#include "shprototypes.h" + +/************************************************************************/ +/* Table of Xinu shell commands and the function associated with each */ +/************************************************************************/ +const struct cmdent cmdtab[] = { + {"memstat", FALSE, xsh_memstat}, /* Make built-in */ + {"editor", FALSE, xsh_editor}, /* Make built-in */ + {"basic", FALSE, xsh_basic}, /* Make built-in */ + {"echo", FALSE, xsh_echo} +// {"argecho", TRUE, xsh_argecho}, +// {"cat", FALSE, xsh_cat}, +// {"clear", TRUE, xsh_clear}, +// {"date", FALSE, xsh_date}, +// {"devdump", FALSE, xsh_devdump}, +// {"echo", FALSE, xsh_echo}, +// {"exit", TRUE, xsh_exit}, +// {"help", FALSE, xsh_help}, +// {"kill", TRUE, xsh_kill}, +// {"memdump", FALSE, xsh_memdump}, +// {"ps", FALSE, xsh_ps}, +// {"sleep", FALSE, xsh_sleep}, +// {"uptime", FALSE, xsh_uptime}, +// {"?", FALSE, xsh_help} + +}; + +uint32 ncmd = sizeof(cmdtab) / sizeof(struct cmdent); + +/************************************************************************/ +/* shell - Provide an interactive user interface that executes */ +/* commands. Each command begins with a command name, has */ +/* a set of optional arguments, has optional input or */ +/* output redirection, and an optional specification for */ +/* background execution (ampersand). The syntax is: */ +/* */ +/* command_name [args*] [redirection] [&] */ +/* */ +/* Redirection is either or both of: */ +/* */ +/* < input_file */ +/* or */ +/* > output_file */ +/* */ +/************************************************************************/ + +process main(void) +{ + char buf[SHELL_BUFLEN]; /* Input line (large enough for */ + int32 len; /* Length of line read */ + char tokbuf[SHELL_BUFLEN + /* Buffer to hold a set of */ + SHELL_MAXTOK]; /* Contiguous null-terminated */ + int32 tlen; /* Current length of all data */ + /* in array tokbuf */ + int32 tok[SHELL_MAXTOK]; /* Index of each token in */ + int32 toktyp[SHELL_MAXTOK]; /* Type of each token in tokbuf */ + int32 ntok; /* Number of tokens on line */ + pid32 child; /* Process ID of spawned child */ + bool8 backgnd; /* Run command in background? */ + char *outname, *inname; /* Pointers to strings for file */ + /* names that follow > and < */ + did32 stdinput, stdoutput; /* Descriptors for redirected */ + /* input and output */ + int32 i; /* Index into array of tokens */ + int32 j; /* Index into array of commands */ + int32 msg; /* Message from receive() for */ + /* child termination */ + int32 tmparg; /* Address of this var is used */ + /* when first creating child */ + /* process, but is replaced */ + char *src, *cmp; /* Pointers used during name */ + /* comparison */ + bool8 diff; /* Was difference found during */ + char *args[SHELL_MAXTOK]; /* Argument vector passed to */ + /* builtin commands */ + did32 dev = 0; /* ID of tty device from which */ + + /* Print shell banner and startup message */ + +/* + fprintf(dev, "\n\n%s%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", + SHELL_BAN0,SHELL_BAN1,SHELL_BAN2,SHELL_BAN3,SHELL_BAN4, + SHELL_BAN5,SHELL_BAN6,SHELL_BAN7,SHELL_BAN8,SHELL_BAN9,SHELL_BAN10); + + fprintf(dev, "%s\n\n", SHELL_STRTMSG); +*/ + + /* Continually prompt the user, read input, and execute command */ + + + while (TRUE) { + + // RAFA + // fprintf(dev, "\033[2J"); + // fprintf(dev, "\033[H"); + + /* Display prompt */ + fprintf(dev, SHELL_PROMPT); + + + len = read(dev, buf, sizeof(buf)); + + /* Exit gracefully on end-of-file */ + + if (len == EOF) { + break; + } + + /* If line contains only NEWLINE, go to next line */ + + if (len <= 1) { + continue; + } + + buf[len] = SH_NEWLINE; /* terminate line */ + + /* Parse input line and divide into tokens */ + + ntok = lexan(buf, len, tokbuf, &tlen, tok, toktyp); + + /* Handle parsing error */ + + if (ntok == SYSERR) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + + /* If line is empty, go to next input line */ + + if (ntok == 0) { + // fprintf(dev, "\n"); + continue; + } + + /* If last token is '&', set background */ + + if (toktyp[ntok-1] == SH_TOK_AMPER) { + ntok-- ; + tlen-= 2; + backgnd = TRUE; + } else { + backgnd = FALSE; + } + + + /* Check for input/output redirection (default is none) */ + + outname = inname = NULL; + if ( (ntok >=3) && ( (toktyp[ntok-2] == SH_TOK_LESS) + ||(toktyp[ntok-2] == SH_TOK_GREATER))){ + if (toktyp[ntok-1] != SH_TOK_OTHER) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + if (toktyp[ntok-2] == SH_TOK_LESS) { + inname = &tokbuf[tok[ntok-1]]; + } else { + outname = &tokbuf[tok[ntok-1]]; + } + ntok -= 2; + tlen = tok[ntok]; + } + + + if ( (ntok >=3) && ( (toktyp[ntok-2] == SH_TOK_LESS) + ||(toktyp[ntok-2] == SH_TOK_GREATER))){ + if (toktyp[ntok-1] != SH_TOK_OTHER) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + if (toktyp[ntok-2] == SH_TOK_LESS) { + if (inname != NULL) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + inname = &tokbuf[tok[ntok-1]]; + } else { + if (outname != NULL) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + outname = &tokbuf[tok[ntok-1]]; + } + ntok -= 2; + tlen = tok[ntok]; + } + + /* Verify remaining tokens are type "other" */ + + for (i=0; i= ncmd) { + // fprintf(dev, "command %s not found\n", tokbuf); + continue; + } + + /* Handle built-in command */ + + if (cmdtab[j].cbuiltin) { /* No background or redirect. */ + if (inname != NULL || outname != NULL || backgnd){ + // fprintf(dev, SHELL_BGERRMSG); + continue; + } else { + /* Set up arg vector for call */ + + for (i=0; i +#include + +#define NLINES 10 +#define LINE_LEN 24 + +void outchar( char ch ); + +#ifndef boolean + #define boolean int + #define true 1 + #define false 0 +#endif + + +#include "text_buffer.h" + +/*------------------------------------------------------------------------ + * xhs_editor - text editor + *------------------------------------------------------------------------ + */ +shellcmd xsh_basic(int nargs, char *args[]) +{ + + int dev = 0; + +// printf("stk: 0x%08x\n", &dev); + + control(dev, TC_MODER, 0, 0); + + setup(); + loop(); + + control(dev, TC_MODEC, 0, 0); + +// printf("stk: 0x%08x\n", &dev); + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +// TinyBasic Plus +//////////////////////////////////////////////////////////////////////////////// +// +// Authors: +// Gordon Brandly (Tiny Basic for 68000) +// Mike Field (Arduino Basic) (port to Arduino) +// Scott Lawrence (TinyBasic Plus) (features, etc) +// +// Contributors: +// Brian O'Dell (INPUT) +// (full list tbd) + +// For full history of Tiny Basic, please see the wikipedia entry here: +// https://en.wikipedia.org/wiki/Tiny_BASIC + +// LICENSING NOTES: +// Mike Field based his C port of Tiny Basic on the 68000 +// Tiny BASIC which carried the following license: +/* +****************************************************************** +* * +* Tiny BASIC for the Motorola MC68000 * +* * +* Derived from Palo Alto Tiny BASIC as published in the May 1976 * +* issue of Dr. Dobb's Journal. Adapted to the 68000 by: * +* Gordon Brandly * +* 12147 - 51 Street * +* Edmonton AB T5W 3G8 * +* Canada * +* (updated mailing address for 1996) * +* * +* This version is for MEX68KECB Educational Computer Board I/O. * +* * +****************************************************************** +* Copyright (C) 1984 by Gordon Brandly. This program may be * +* freely distributed for personal use only. All commercial * +* rights are reserved. * +****************************************************************** +*/ +// ref: http://members.shaw.ca:80/gbrandly/68ktinyb.html +// +// However, Mike did not include a license of his own for his +// version of this. +// ref: http://hamsterworks.co.nz/mediawiki/index.php/Arduino_Basic +// +// From discussions with him, I felt that the MIT license is +// the most applicable to his intent. +// +// I am in the process of further determining what should be +// done wrt licensing further. This entire header will likely +// change with the next version 0.16, which will hopefully nail +// down the whole thing so we can get back to implementing +// features instead of licenses. Thank you for your time. + +#define kVersion "v0.15" + +// v0.15: 2018-06-23 +// Integrating some contributions +// Corrected some of the #ifdef nesting atop this page +// Licensing issues beginning to be addressed + +// v0.14: 2013-11-07 +// Modified Input command to accept an expression using getn() +// Syntax is "input x" where x is any variable +// NOTE: This only works for numbers, expressions. not strings. +// +// v0.13: 2013-03-04 +// Support for Arduino 1.5 (SPI.h included, additional changes for DUE support) +// +// v0.12: 2013-03-01 +// EEPROM load and save routines added: EFORMAT, ELIST, ELOAD, ESAVE, ECHAIN +// added EAUTORUN option (chains to EEProm saved program on startup) +// Bugfixes to build properly on non-arduino systems (PROGMEM #define workaround) +// cleaned up a bit of the #define options wrt TONE +// +// v0.11: 2013-02-20 +// all display strings and tables moved to PROGMEM to save space +// removed second serial +// removed pinMode completely, autoconf is explicit +// beginnings of EEPROM related functionality (new,load,save,list) +// +// v0.10: 2012-10-15 +// added kAutoConf, which eliminates the "PINMODE" statement. +// now, DWRITE,DREAD,AWRITE,AREAD automatically set the PINMODE appropriately themselves. +// should save a few bytes in your programs. +// +// v0.09: 2012-10-12 +// Fixed directory listings. FILES now always works. (bug in the SD library) +// ref: http://arduino.cc/forum/index.php/topic,124739.0.html +// fixed filesize printouts (added printUnum for unsigned numbers) +// #defineable baud rate for slow connection throttling +//e +// v0.08: 2012-10-02 +// Tone generation through piezo added (TONE, TONEW, NOTONE) +// +// v0.07: 2012-09-30 +// Autorun buildtime configuration feature +// +// v0.06: 2012-09-27 +// Added optional second serial input, used for an external keyboard +// +// v0.05: 2012-09-21 +// CHAIN to load and run a second file +// RND,RSEED for random stuff +// Added "!=" for "<>" synonym +// Added "END" for "STOP" synonym (proper name for the functionality anyway) +// +// v0.04: 2012-09-20 +// DELAY ms - for delaying +// PINMODE , INPUT|IN|I|OUTPUT|OUT|O +// DWRITE , HIGH|HI|1|LOW|LO|0 +// AWRITE , [0..255] +// fixed "save" appending to existing files instead of overwriting +// Updated for building desktop command line app (incomplete) +// +// v0.03: 2012-09-19 +// Integrated Jurg Wullschleger whitespace,unary fix +// Now available through github +// Project renamed from "Tiny Basic in C" to "TinyBasic Plus" +// +// v0.02b: 2012-09-17 Scott Lawrence +// Better FILES listings +// +// v0.02a: 2012-09-17 Scott Lawrence +// Support for SD Library +// Added: SAVE, FILES (mostly works), LOAD (mostly works) (redirects IO) +// Added: MEM, ? (PRINT) +// Quirk: "10 LET A=B+C" is ok "10 LET A = B + C" is not. +// Quirk: INPUT seems broken? + +// IF testing with Visual C, this needs to be the first thing in the file. +//#include "stdafx.h" + +// char eliminateCompileErrors = 1; // fix to suppress arduino build errors + +// hack to let makefiles work with this file unchanged +#undef ARDUINO + + +//////////////////////////////////////////////////////////////////////////////// +// Feature option configuration... + +// This enables LOAD, SAVE, FILES commands through the Arduino SD Library +// it adds 9k of usage as well. +//#define ENABLE_FILEIO 1 +#undef ENABLE_FILEIO + +// this turns on "autorun". if there's FileIO, and a file "autorun.bas", +// then it will load it and run it when starting up +//#define ENABLE_AUTORUN 1 +#undef ENABLE_AUTORUN + +// this will enable the "TONE", "NOTONE" command using a piezo +// element on the specified pin. Wire the red/positive/piezo to the kPiezoPin, +// and the black/negative/metal disc to ground. +// it adds 1.5k of usage as well. +//#define ENABLE_TONES 1 +#define kPiezoPin 5 + +// we can use the EEProm to store a program during powerdown. This is +// 1kbyte on the '328, and 512 bytes on the '168. Enabling this here will +// allow for this funcitonality to work. Note that this only works on AVR +// arduino. Disable it for DUE/other devices. + +// Sometimes, we connect with a slower device as the console. +// Set your console D0/D1 baud rate here (9600 baud default) +#define kConsoleBaud 9600 + + + +// Enable memory alignment for certain processers (e.g. some ESP8266-based devices) +#ifdef ESP8266 + // Uses up to one extra byte per program line of memory + #define ALIGN_MEMORY 1 +#else + #undef ALIGN_MEMORY +#endif + + // not an arduino, so we can disable these features. + // turn off EEProm +#undef ENABLE_EEPROM +#undef ENABLE_TONES + + +// includes, and settings for Arduino-specific features + + +// set up file includes for things we need, or desktop specific stuff. + +#include +#include + +// size of our program ram +// RAFA #define kRamSize 64*1024 /* arbitrary - not dependant on libraries */ +// RAFA #define kRamSize 24 /* arbitrary - not dependant on libraries */ + + +// RAFA AGREGA +// #define ALIGN_MEMORY 1 + +//////////////////// + +// memory alignment +// necessary for some esp8266-based devices +#ifdef ALIGN_MEMORY + // Align memory addess x to an even page + #define ALIGN_UP(x) ((unsigned char*)(((unsigned int)(x + 1) >> 1) << 1)) + #define ALIGN_DOWN(x) ((unsigned char*)(((unsigned int)x >> 1) << 1)) +#else + #define ALIGN_UP(x) x + #define ALIGN_DOWN(x) x +#endif + + +//////////////////// +// various other desktop-tweaks and such. + +#ifndef boolean + #define boolean int + #define true 1 + #define false 0 +#endif + +#ifndef byte + typedef unsigned char byte; +#endif + +// some catches for AVR based text string stuff... +#ifndef PROGMEM + #define PROGMEM +#endif + +#ifndef pgm_read_byte + #define pgm_read_byte( A ) *(A) +#endif + +//////////////////// + + +// some settings based things + +boolean inhibitOutput = false; +static boolean runAfterLoad = false; +static boolean triggerRun = false; + +// these will select, at runtime, where IO happens through for load/save +enum { + kStreamSerial = 0, + kStreamEEProm, + kStreamFile +}; +static unsigned char inStream = kStreamSerial; +static unsigned char outStream = kStreamSerial; + + +//////////////////////////////////////////////////////////////////////////////// +// ASCII Characters +#define CR '\r' +#define NL '\n' +#define LF 0x0a +#define TAB '\t' +#define BELL '\b' +#define SPACE ' ' +#define SQUOTE '\'' +#define DQUOTE '\"' +#define CTRLC 0x03 +#define CTRLH 0x08 +#define CTRLS 0x13 +#define CTRLX 0x18 + +typedef short unsigned LINENUM; +#define ECHO_CHARS 0 + +// RAFA +//unsigned char program[kRamSize]; +// extern unsigned char program[NLINES*LINE_LEN]; + +static const char * sentinel = "HELLO"; +static unsigned char *txtpos,*list_line, *tmptxtpos; +static unsigned char expression_error; +static unsigned char *tempsp; + +/***********************************************************/ +// Keyword table and constants - the last character has 0x80 added to it +const static unsigned char keywords[] PROGMEM = { + 'L','I','S','T'+0x80, + 'L','O','A','D'+0x80, + 'N','E','W'+0x80, + 'R','U','N'+0x80, + 'S','A','V','E'+0x80, + 'N','E','X','T'+0x80, + 'L','E','T'+0x80, + 'I','F'+0x80, + 'G','O','T','O'+0x80, + 'G','O','S','U','B'+0x80, + 'R','E','T','U','R','N'+0x80, + 'R','E','M'+0x80, + 'F','O','R'+0x80, + 'I','N','P','U','T'+0x80, + 'P','R','I','N','T'+0x80, + 'P','O','K','E'+0x80, + 'S','T','O','P'+0x80, + 'B','Y','E'+0x80, + 'F','I','L','E','S'+0x80, + 'M','E','M'+0x80, + '?'+ 0x80, + '\''+ 0x80, + 'A','W','R','I','T','E'+0x80, + 'D','W','R','I','T','E'+0x80, + 'D','E','L','A','Y'+0x80, + 'E','N','D'+0x80, + 'R','S','E','E','D'+0x80, + 'C','H','A','I','N'+0x80, +#ifdef ENABLE_TONES + 'T','O','N','E','W'+0x80, + 'T','O','N','E'+0x80, + 'N','O','T','O','N','E'+0x80, +#endif + 0 +}; + +// by moving the command list to an enum, we can easily remove sections +// above and below simultaneously to selectively obliterate functionality. +enum { + KW_LIST = 0, + KW_LOAD, KW_NEW, KW_RUN, KW_SAVE, + KW_NEXT, KW_LET, KW_IF, + KW_GOTO, KW_GOSUB, KW_RETURN, + KW_REM, + KW_FOR, + KW_INPUT, KW_PRINT, + KW_POKE, + KW_STOP, KW_BYE, + KW_FILES, + KW_MEM, + KW_QMARK, KW_QUOTE, + KW_AWRITE, KW_DWRITE, + KW_DELAY, + KW_END, + KW_RSEED, + KW_CHAIN, +#ifdef ENABLE_TONES + KW_TONEW, KW_TONE, KW_NOTONE, +#endif + KW_DEFAULT /* always the final one*/ +}; + +struct stack_for_frame { + char frame_type; + char for_var; + short int terminal; + short int step; + unsigned char *current_line; + unsigned char *txtpos; +}; + +struct stack_gosub_frame { + char frame_type; + unsigned char *current_line; + unsigned char *txtpos; +}; + +const static unsigned char func_tab[] PROGMEM = { + 'P','E','E','K'+0x80, + 'A','B','S'+0x80, + 'A','R','E','A','D'+0x80, + 'D','R','E','A','D'+0x80, + 'R','N','D'+0x80, + 0 +}; +#define FUNC_PEEK 0 +#define FUNC_ABS 1 +#define FUNC_AREAD 2 +#define FUNC_DREAD 3 +#define FUNC_RND 4 +#define FUNC_UNKNOWN 5 + +const static unsigned char to_tab[] PROGMEM = { + 'T','O'+0x80, + 0 +}; + +const static unsigned char step_tab[] PROGMEM = { + 'S','T','E','P'+0x80, + 0 +}; + +const static unsigned char relop_tab[] PROGMEM = { + '>','='+0x80, + '<','>'+0x80, + '>'+0x80, + '='+0x80, + '<','='+0x80, + '<'+0x80, + '!','='+0x80, + 0 +}; + +#define RELOP_GE 0 +#define RELOP_NE 1 +#define RELOP_GT 2 +#define RELOP_EQ 3 +#define RELOP_LE 4 +#define RELOP_LT 5 +#define RELOP_NE_BANG 6 +#define RELOP_UNKNOWN 7 + +const static unsigned char highlow_tab[] PROGMEM = { + 'H','I','G','H'+0x80, + 'H','I'+0x80, + 'L','O','W'+0x80, + 'L','O'+0x80, + 0 +}; +#define HIGHLOW_HIGH 1 +#define HIGHLOW_UNKNOWN 4 + +//RAFA ANTES DECIA 5 +//#define STACK_SIZE (sizeof(struct stack_for_frame)*5) +#define STACK_SIZE (sizeof(struct stack_for_frame)*4) + + +#define VAR_SIZE sizeof(short int) // Size of variables in bytes + +static unsigned char *stack_limit; +static unsigned char *program_start; +static unsigned char *program_end; +// static unsigned char *stack; // Software stack for things that should go on the CPU stack +static unsigned char *variables_begin; +static unsigned char *current_line; +static unsigned char *sp; +#define STACK_GOSUB_FLAG 'G' +#define STACK_FOR_FLAG 'F' +static unsigned char table_index; +static LINENUM linenum; + +static const unsigned char okmsg[] PROGMEM = "OK"; +static const unsigned char whatmsg[] PROGMEM = "What? "; +static const unsigned char howmsg[] PROGMEM = "How?"; +static const unsigned char sorrymsg[] PROGMEM = "Sorry!"; +static const unsigned char initmsg[] PROGMEM = "TinyBasic Plus " kVersion; +static const unsigned char memorymsg[] PROGMEM = " bytes free."; +static const unsigned char breakmsg[] PROGMEM = "break!"; +static const unsigned char unimplimentedmsg[] PROGMEM = "Unimplemented"; +static const unsigned char backspacemsg[] PROGMEM = "\b \b"; +static const unsigned char indentmsg[] PROGMEM = " "; +static const unsigned char sderrormsg[] PROGMEM = "SD card error."; +static const unsigned char sdfilemsg[] PROGMEM = "SD file error."; +static const unsigned char dirextmsg[] PROGMEM = "(dir)"; +static const unsigned char slashmsg[] PROGMEM = "/"; +static const unsigned char spacemsg[] PROGMEM = " "; + +static int inchar(void); +//static void outchar(unsigned char c); +static void line_terminator(void); +static short int expression(void); +static unsigned char breakcheck(void); +/***************************************************************************/ +static void ignore_blanks(void) +{ + while(*txtpos == SPACE || *txtpos == TAB) + txtpos++; +} + + +/***************************************************************************/ +static void scantable(const unsigned char *table) +{ + int i = 0; + table_index = 0; + while(1) + { + // Run out of table entries? + if(pgm_read_byte( table ) == 0) + return; + + // Do we match this character? + if(txtpos[i] == pgm_read_byte( table )) + { + i++; + table++; + } + else + { + // do we match the last character of keywork (with 0x80 added)? If so, return + if(txtpos[i]+0x80 == pgm_read_byte( table )) + { + txtpos += i+1; // Advance the pointer to following the keyword + ignore_blanks(); + return; + } + + // Forward to the end of this keyword + while((pgm_read_byte( table ) & 0x80) == 0) + table++; + + // Now move on to the first character of the next word, and reset the position index + table++; + table_index++; + ignore_blanks(); + i = 0; + } + } +} + +/***************************************************************************/ +static void pushb(unsigned char b) +{ + sp--; + *sp = b; +} + +/***************************************************************************/ +static unsigned char popb() +{ + unsigned char b; + b = *sp; + sp++; + return b; +} + +/***************************************************************************/ +void printnum(int num) +{ + int digits = 0; + + if(num < 0) + { + num = -num; + outchar('-'); + } + do { + pushb(num%10+'0'); + num = num/10; + digits++; + } + while (num > 0); + + while(digits > 0) + { + outchar(popb()); + digits--; + } +} + +void printUnum(unsigned int num) +{ + int digits = 0; + + do { + pushb(num%10+'0'); + num = num/10; + digits++; + } + while (num > 0); + + while(digits > 0) + { + outchar(popb()); + digits--; + } +} + +/***************************************************************************/ +static unsigned short testnum(void) +{ + unsigned short num = 0; + ignore_blanks(); + + while(*txtpos>= '0' && *txtpos <= '9' ) + { + // Trap overflows + if(num >= 0xFFFF/10) + { + num = 0xFFFF; + break; + } + + num = num *10 + *txtpos - '0'; + txtpos++; + } + return num; +} + +/***************************************************************************/ +static unsigned char print_quoted_string(void) +{ + int i=0; + unsigned char delim = *txtpos; + if(delim != '"' && delim != '\'') + return 0; + txtpos++; + + // Check we have a closing delimiter + while(txtpos[i] != delim) + { + if(txtpos[i] == NL) + return 0; + i++; + } + + // Print the characters + while(*txtpos != delim) + { + outchar(*txtpos); + txtpos++; + } + txtpos++; // Skip over the last delimiter + + return 1; +} + + +/***************************************************************************/ +void printmsgNoNL(const unsigned char *msg) +{ + while( pgm_read_byte( msg ) != 0 ) { + outchar( pgm_read_byte( msg++ ) ); + }; +} + +/***************************************************************************/ +void printmsg(const unsigned char *msg) +{ + printmsgNoNL(msg); + line_terminator(); +} + +/***************************************************************************/ +static void getln(char prompt) +{ + char s = ' '; + outchar(prompt); + outchar(s); + txtpos = program_end+sizeof(LINENUM); + + while(1) + { + char c = inchar(); + switch(c) + { + case NL: + //break; + case CR: + line_terminator(); + // Terminate all strings with a NL + txtpos[0] = NL; + return; + case CTRLH: + if(txtpos == program_end) + break; + txtpos--; + + printmsg(backspacemsg); + break; + default: + // We need to leave at least one space to allow us to shuffle the line into order + if(txtpos == variables_begin-2) + outchar(BELL); + else + { + txtpos[0] = c; + txtpos++; + outchar(c); + } + } + } +} + +/***************************************************************************/ +static unsigned char *findline(void) +{ + unsigned char *line = program_start; + while(1) + { + if(line == program_end) + return line; + + if(((LINENUM *)line)[0] >= linenum) + return line; + + // Add the line length onto the current address, to get to the next line; + line += line[sizeof(LINENUM)]; + } +} + +/***************************************************************************/ +static void toUppercaseBuffer(void) +{ + unsigned char *c = program_end+sizeof(LINENUM); + unsigned char quote = 0; + + while(*c != NL) + { + // Are we in a quoted string? + if(*c == quote) + quote = 0; + else if(*c == '"' || *c == '\'') + quote = *c; + else if(quote == 0 && *c >= 'a' && *c <= 'z') + *c = *c + 'A' - 'a'; + c++; + } +} + +/***************************************************************************/ +void printline() +{ + LINENUM line_num; + + line_num = *((LINENUM *)(list_line)); + list_line += sizeof(LINENUM) + sizeof(char); + + // Output the line */ + printnum(line_num); + outchar(' '); + while(*list_line != NL) + { + outchar(*list_line); + list_line++; + } + list_line++; +#ifdef ALIGN_MEMORY + // Start looking for next line on even page + if (ALIGN_UP(list_line) != list_line) + list_line++; +#endif + line_terminator(); +} + +/***************************************************************************/ +static short int expr4(void) +{ + // fix provided by Jurg Wullschleger wullschleger@gmail.com + // fixes whitespace and unary operations + ignore_blanks(); + + if( *txtpos == '-' ) { + txtpos++; + return -expr4(); + } + // end fix + + if(*txtpos == '0') + { + txtpos++; + return 0; + } + + if(*txtpos >= '1' && *txtpos <= '9') + { + short int a = 0; + do { + a = a*10 + *txtpos - '0'; + txtpos++; + } + while(*txtpos >= '0' && *txtpos <= '9'); + return a; + } + + // Is it a function or variable reference? + if(txtpos[0] >= 'A' && txtpos[0] <= 'Z') + { + short int a; + // Is it a variable reference (single alpha) + if(txtpos[1] < 'A' || txtpos[1] > 'Z') + { + a = ((short int *)variables_begin)[*txtpos - 'A']; + txtpos++; + return a; + } + + // Is it a function with a single parameter + scantable(func_tab); + if(table_index == FUNC_UNKNOWN) + goto expr4_error; + + unsigned char f = table_index; + + if(*txtpos != '(') + goto expr4_error; + + txtpos++; + a = expression(); + if(*txtpos != ')') + goto expr4_error; + txtpos++; + switch(f) + { + case FUNC_PEEK: +// RAFA return program[a]; + return 0; + + case FUNC_ABS: + if(a < 0) + return -a; + return a; + + + case FUNC_RND: + return( rand() % a ); + } + } + + if(*txtpos == '(') + { + short int a; + txtpos++; + a = expression(); + if(*txtpos != ')') + goto expr4_error; + + txtpos++; + return a; + } + +expr4_error: + expression_error = 1; + return 0; + +} + +/***************************************************************************/ +static short int expr3(void) +{ + short int a,b; + + a = expr4(); + + ignore_blanks(); // fix for eg: 100 a = a + 1 + + while(1) + { + if(*txtpos == '*') + { + txtpos++; + b = expr4(); + a *= b; + } + else if(*txtpos == '/') + { + txtpos++; + b = expr4(); + if(b != 0) + a /= b; + else + expression_error = 1; + } + else + return a; + } +} + +/***************************************************************************/ +static short int expr2(void) +{ + short int a,b; + + if(*txtpos == '-' || *txtpos == '+') + a = 0; + else + a = expr3(); + + while(1) + { + if(*txtpos == '-') + { + txtpos++; + b = expr3(); + a -= b; + } + else if(*txtpos == '+') + { + txtpos++; + b = expr3(); + a += b; + } + else + return a; + } +} +/***************************************************************************/ +static short int expression(void) +{ + short int a,b; + + a = expr2(); + + // Check if we have an error + if(expression_error) return a; + + scantable(relop_tab); + if(table_index == RELOP_UNKNOWN) + return a; + + switch(table_index) + { + case RELOP_GE: + b = expr2(); + if(a >= b) return 1; + break; + case RELOP_NE: + case RELOP_NE_BANG: + b = expr2(); + if(a != b) return 1; + break; + case RELOP_GT: + b = expr2(); + if(a > b) return 1; + break; + case RELOP_EQ: + b = expr2(); + if(a == b) return 1; + break; + case RELOP_LE: + b = expr2(); + if(a <= b) return 1; + break; + case RELOP_LT: + b = expr2(); + if(a < b) return 1; + break; + } + return 0; +} + +/***************************************************************************/ +void loop() +{ + unsigned char *start; + unsigned char *newEnd; + unsigned char linelen; + boolean isDigital; + boolean alsoWait = false; + int val; + + unsigned char program[NLINES*LINE_LEN]; + + program_start = program; + program_end = program_start; + sp = program+sizeof(program); // Needed for printnum +#ifdef ALIGN_MEMORY + // Ensure these memory blocks start on even pages + stack_limit = ALIGN_DOWN(program+sizeof(program)-STACK_SIZE); + variables_begin = ALIGN_DOWN(stack_limit - 27*VAR_SIZE); +#else + stack_limit = program+sizeof(program)-STACK_SIZE; + variables_begin = stack_limit - 27*VAR_SIZE; +#endif + + // memory free + printnum(variables_begin-program_end); + printmsg(memorymsg); + +warmstart: + // this signifies that it is running in 'direct' mode. + current_line = 0; + sp = program+sizeof(program); + printmsg(okmsg); + +prompt: + if( triggerRun ){ + triggerRun = false; + current_line = program_start; + goto execline; + } + + getln( '>' ); + toUppercaseBuffer(); + + txtpos = program_end+sizeof(unsigned short); + + // Find the end of the freshly entered line + while(*txtpos != NL) + txtpos++; + + // Move it to the end of program_memory + { + unsigned char *dest; + dest = variables_begin-1; + while(1) + { + *dest = *txtpos; + if(txtpos == program_end+sizeof(unsigned short)) + break; + dest--; + txtpos--; + } + txtpos = dest; + } + + // Now see if we have a line number + linenum = testnum(); + ignore_blanks(); + if(linenum == 0) + goto direct; + + if(linenum == 0xFFFF) + goto qhow; + + // Find the length of what is left, including the (yet-to-be-populated) line header + linelen = 0; + while(txtpos[linelen] != NL) + linelen++; + linelen++; // Include the NL in the line length + linelen += sizeof(unsigned short)+sizeof(char); // Add space for the line number and line length + + // Now we have the number, add the line header. + txtpos -= 3; + +#ifdef ALIGN_MEMORY + // Line starts should always be on 16-bit pages + if (ALIGN_DOWN(txtpos) != txtpos) + { + txtpos--; + linelen++; + // As the start of the line has moved, the data should move as well + unsigned char *tomove; + tomove = txtpos + 3; + while (tomove < txtpos + linelen - 1) + { + *tomove = *(tomove + 1); + tomove++; + } + } +#endif + + *((unsigned short *)txtpos) = linenum; + txtpos[sizeof(LINENUM)] = linelen; + + + // Merge it into the rest of the program + start = findline(); + + // If a line with that number exists, then remove it + if(start != program_end && *((LINENUM *)start) == linenum) + { + unsigned char *dest, *from; + unsigned tomove; + + from = start + start[sizeof(LINENUM)]; + dest = start; + + tomove = program_end - from; + while( tomove > 0) + { + *dest = *from; + from++; + dest++; + tomove--; + } + program_end = dest; + } + + if(txtpos[sizeof(LINENUM)+sizeof(char)] == NL) // If the line has no txt, it was just a delete + goto prompt; + + + + // Make room for the new line, either all in one hit or lots of little shuffles + while(linelen > 0) + { + unsigned int tomove; + unsigned char *from,*dest; + unsigned int space_to_make; + + space_to_make = txtpos - program_end; + + if(space_to_make > linelen) + space_to_make = linelen; + newEnd = program_end+space_to_make; + tomove = program_end - start; + + + // Source and destination - as these areas may overlap we need to move bottom up + from = program_end; + dest = newEnd; + while(tomove > 0) + { + from--; + dest--; + *dest = *from; + tomove--; + } + + // Copy over the bytes into the new space + for(tomove = 0; tomove < space_to_make; tomove++) + { + *start = *txtpos; + txtpos++; + start++; + linelen--; + } + program_end = newEnd; + } + goto prompt; + +unimplemented: + printmsg(unimplimentedmsg); + goto prompt; + +qhow: + printmsg(howmsg); + goto prompt; + +qwhat: + printmsgNoNL(whatmsg); + if(current_line != NULL) + { + unsigned char tmp = *txtpos; + if(*txtpos != NL) + *txtpos = '^'; + list_line = current_line; + printline(); + *txtpos = tmp; + } + line_terminator(); + goto prompt; + +qsorry: + printmsg(sorrymsg); + goto warmstart; + +run_next_statement: + while(*txtpos == ':') + txtpos++; + ignore_blanks(); + if(*txtpos == NL) + goto execnextline; + goto interperateAtTxtpos; + +direct: + txtpos = program_end+sizeof(LINENUM); + if(*txtpos == NL) + goto prompt; + +interperateAtTxtpos: + if(breakcheck()) + { + printmsg(breakmsg); + goto warmstart; + } + + scantable(keywords); + +// RAFA +// short int val; +// int stk2 = 4; + + switch(table_index) + { + case KW_DELAY: + { + goto unimplemented; + } + + case KW_FILES: + goto files; + case KW_LIST: + goto list; + case KW_CHAIN: + goto chain; + case KW_LOAD: + goto load; + case KW_MEM: + goto mem; + case KW_NEW: + if(txtpos[0] != NL) + goto qwhat; + program_end = program_start; + goto prompt; + case KW_RUN: + current_line = program_start; + goto execline; + case KW_SAVE: + goto save; + case KW_NEXT: + goto next; + case KW_LET: + goto assignment; + case KW_IF: + // short int val; + expression_error = 0; + val = expression(); + if(expression_error || *txtpos == NL) + goto qhow; + if(val != 0) + goto interperateAtTxtpos; + goto execnextline; + + case KW_GOTO: + expression_error = 0; + linenum = expression(); + if(expression_error || *txtpos != NL) + goto qhow; + current_line = findline(); + goto execline; + + case KW_GOSUB: + goto gosub; + case KW_RETURN: + goto gosub_return; + case KW_REM: + case KW_QUOTE: + goto execnextline; // Ignore line completely + case KW_FOR: + goto forloop; + case KW_INPUT: + goto input; + case KW_PRINT: + case KW_QMARK: + goto print; + case KW_POKE: + goto poke; + case KW_END: + case KW_STOP: + // This is the easy way to end - set the current line to the end of program attempt to run it + if(txtpos[0] != NL) + goto qwhat; + current_line = program_end; + goto execline; + case KW_BYE: +// printf("stk2: 0x%08x\n", &stk2); + // Leave the basic interperater + return; + + case KW_AWRITE: // AWRITE , HIGH|LOW + isDigital = false; + goto awrite; + case KW_DWRITE: // DWRITE , HIGH|LOW + isDigital = true; + goto dwrite; + + case KW_RSEED: + goto rseed; + +#ifdef ENABLE_TONES + case KW_TONEW: + alsoWait = true; + case KW_TONE: + goto tonegen; + case KW_NOTONE: + goto tonestop; +#endif + + + case KW_DEFAULT: + goto assignment; + default: + break; + } + +execnextline: + if(current_line == NULL) // Processing direct commands? + goto prompt; + current_line += current_line[sizeof(LINENUM)]; + +execline: + if(current_line == program_end) // Out of lines to run + goto warmstart; + txtpos = current_line+sizeof(LINENUM)+sizeof(char); + goto interperateAtTxtpos; + + +input: + { + unsigned char var; + int value; + ignore_blanks(); + if(*txtpos < 'A' || *txtpos > 'Z') + goto qwhat; + var = *txtpos; + txtpos++; + ignore_blanks(); + if(*txtpos != NL && *txtpos != ':') + goto qwhat; +inputagain: + tmptxtpos = txtpos; + getln( '?' ); + toUppercaseBuffer(); + txtpos = program_end+sizeof(unsigned short); + ignore_blanks(); + expression_error = 0; + value = expression(); + if(expression_error) + goto inputagain; + ((short int *)variables_begin)[var-'A'] = value; + txtpos = tmptxtpos; + + goto run_next_statement; + } + +forloop: + { + unsigned char var; + short int initial, step, terminal; + ignore_blanks(); + if(*txtpos < 'A' || *txtpos > 'Z') + goto qwhat; + var = *txtpos; + txtpos++; + ignore_blanks(); + if(*txtpos != '=') + goto qwhat; + txtpos++; + ignore_blanks(); + + expression_error = 0; + initial = expression(); + if(expression_error) + goto qwhat; + + scantable(to_tab); + if(table_index != 0) + goto qwhat; + + terminal = expression(); + if(expression_error) + goto qwhat; + + scantable(step_tab); + if(table_index == 0) + { + step = expression(); + if(expression_error) + goto qwhat; + } + else + step = 1; + ignore_blanks(); + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + + + if(!expression_error && *txtpos == NL) + { + struct stack_for_frame *f; + if(sp + sizeof(struct stack_for_frame) < stack_limit) + goto qsorry; + + sp -= sizeof(struct stack_for_frame); + f = (struct stack_for_frame *)sp; + ((short int *)variables_begin)[var-'A'] = initial; + f->frame_type = STACK_FOR_FLAG; + f->for_var = var; + f->terminal = terminal; + f->step = step; + f->txtpos = txtpos; + f->current_line = current_line; + goto run_next_statement; + } + } + goto qhow; + +gosub: + expression_error = 0; + linenum = expression(); + if(!expression_error && *txtpos == NL) + { + struct stack_gosub_frame *f; + if(sp + sizeof(struct stack_gosub_frame) < stack_limit) + goto qsorry; + + sp -= sizeof(struct stack_gosub_frame); + f = (struct stack_gosub_frame *)sp; + f->frame_type = STACK_GOSUB_FLAG; + f->txtpos = txtpos; + f->current_line = current_line; + current_line = findline(); + goto execline; + } + goto qhow; + +next: + // Fnd the variable name + ignore_blanks(); + if(*txtpos < 'A' || *txtpos > 'Z') + goto qhow; + txtpos++; + ignore_blanks(); + if(*txtpos != ':' && *txtpos != NL) + goto qwhat; + +gosub_return: + // Now walk up the stack frames and find the frame we want, if present + tempsp = sp; + while(tempsp < program+sizeof(program)-1) + { + switch(tempsp[0]) + { + case STACK_GOSUB_FLAG: + if(table_index == KW_RETURN) + { + struct stack_gosub_frame *f = (struct stack_gosub_frame *)tempsp; + current_line = f->current_line; + txtpos = f->txtpos; + sp += sizeof(struct stack_gosub_frame); + goto run_next_statement; + } + // This is not the loop you are looking for... so Walk back up the stack + tempsp += sizeof(struct stack_gosub_frame); + break; + case STACK_FOR_FLAG: + // Flag, Var, Final, Step + if(table_index == KW_NEXT) + { + struct stack_for_frame *f = (struct stack_for_frame *)tempsp; + // Is the the variable we are looking for? + if(txtpos[-1] == f->for_var) + { + short int *varaddr = ((short int *)variables_begin) + txtpos[-1] - 'A'; + *varaddr = *varaddr + f->step; + // Use a different test depending on the sign of the step increment + if((f->step > 0 && *varaddr <= f->terminal) || (f->step < 0 && *varaddr >= f->terminal)) + { + // We have to loop so don't pop the stack + txtpos = f->txtpos; + current_line = f->current_line; + goto run_next_statement; + } + // We've run to the end of the loop. drop out of the loop, popping the stack + sp = tempsp + sizeof(struct stack_for_frame); + goto run_next_statement; + } + } + // This is not the loop you are looking for... so Walk back up the stack + tempsp += sizeof(struct stack_for_frame); + break; + default: + //printf("Stack is stuffed!\n"); + goto warmstart; + } + } + // Didn't find the variable we've been looking for + goto qhow; + +assignment: + { + short int value; + short int *var; + + if(*txtpos < 'A' || *txtpos > 'Z') + goto qhow; + var = (short int *)variables_begin + *txtpos - 'A'; + txtpos++; + + ignore_blanks(); + + if (*txtpos != '=') + goto qwhat; + txtpos++; + ignore_blanks(); + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + // Check that we are at the end of the statement + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + *var = value; + } + goto run_next_statement; +poke: + { + short int value; + unsigned char *address; + + // Work out where to put it + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + address = (unsigned char *)value; + + // check for a comma + ignore_blanks(); + if (*txtpos != ',') + goto qwhat; + txtpos++; + ignore_blanks(); + + // Now get the value to assign + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + //printf("Poke %p value %i\n",address, (unsigned char)value); + // Check that we are at the end of the statement + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + } + goto run_next_statement; + +list: + linenum = testnum(); // Retuns 0 if no line found. + + // Should be EOL + if(txtpos[0] != NL) + goto qwhat; + + // Find the line + list_line = findline(); + while(list_line != program_end) + printline(); + goto warmstart; + +print: + // If we have an empty list then just put out a NL + if(*txtpos == ':' ) + { + line_terminator(); + txtpos++; + goto run_next_statement; + } + if(*txtpos == NL) + { + goto execnextline; + } + + while(1) + { + ignore_blanks(); + if(print_quoted_string()) + { + ; + } + else if(*txtpos == '"' || *txtpos == '\'') + goto qwhat; + else + { + short int e; + expression_error = 0; + e = expression(); + if(expression_error) + goto qwhat; + printnum(e); + } + + // At this point we have three options, a comma or a new line + if(*txtpos == ',') + txtpos++; // Skip the comma and move onto the next + else if(txtpos[0] == ';' && (txtpos[1] == NL || txtpos[1] == ':')) + { + txtpos++; // This has to be the end of the print - no newline + break; + } + else if(*txtpos == NL || *txtpos == ':') + { + line_terminator(); // The end of the print statement + break; + } + else + goto qwhat; + } + goto run_next_statement; + +mem: + // memory free + printnum(variables_begin-program_end); + printmsg(memorymsg); + goto run_next_statement; + + + /*************************************************/ + +pinmode: // PINMODE , I/O +awrite: // AWRITE ,val +dwrite: + goto unimplemented; + + /*************************************************/ +files: + // display a listing of files on the device. + // version 1: no support for subdirectories + + goto unimplemented; + + +chain: + runAfterLoad = true; + +load: + // clear the program + program_end = program_start; + + // load from a file into memory + goto unimplemented; + + + +save: + // save from memory out to a file + goto unimplemented; + +rseed: + { + short int value; + + //Get the pin number + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + + srand( value ); + goto run_next_statement; + } + +#ifdef ENABLE_TONES +tonestop: + noTone( kPiezoPin ); + goto run_next_statement; + +tonegen: + { + // TONE freq, duration + // if either are 0, tones turned off + short int freq; + short int duration; + + //Get the frequency + expression_error = 0; + freq = expression(); + if(expression_error) + goto qwhat; + + ignore_blanks(); + if (*txtpos != ',') + goto qwhat; + txtpos++; + ignore_blanks(); + + + //Get the duration + expression_error = 0; + duration = expression(); + if(expression_error) + goto qwhat; + + if( freq == 0 || duration == 0 ) + goto tonestop; + + tone( kPiezoPin, freq, duration ); + if( alsoWait ) { + delay( duration ); + alsoWait = false; + } + goto run_next_statement; + } +#endif /* ENABLE_TONES */ +} + +// returns 1 if the character is valid in a filename +static int isValidFnChar( char c ) +{ + if( c >= '0' && c <= '9' ) return 1; // number + if( c >= 'A' && c <= 'Z' ) return 1; // LETTER + if( c >= 'a' && c <= 'z' ) return 1; // letter (for completeness) + if( c == '_' ) return 1; + if( c == '+' ) return 1; + if( c == '.' ) return 1; + if( c == '~' ) return 1; // Window~1.txt + + return 0; +} + +unsigned char * filenameWord(void) +{ + // SDL - I wasn't sure if this functionality existed above, so I figured i'd put it here + unsigned char * ret = txtpos; + expression_error = 0; + + // make sure there are no quotes or spaces, search for valid characters + //while(*txtpos == SPACE || *txtpos == TAB || *txtpos == SQUOTE || *txtpos == DQUOTE ) txtpos++; + while( !isValidFnChar( *txtpos )) txtpos++; + ret = txtpos; + + if( *ret == '\0' ) { + expression_error = 1; + return ret; + } + + // now, find the next nonfnchar + txtpos++; + while( isValidFnChar( *txtpos )) txtpos++; + if( txtpos != ret ) *txtpos = '\0'; + + // set the error code if we've got no string + if( *ret == '\0' ) { + expression_error = 1; + } + + return ret; +} + +/***************************************************************************/ +static void line_terminator(void) +{ + outchar(NL); + outchar(CR); +} + +/***********************************************************/ +void setup() +{ +} + + +/***********************************************************/ +static unsigned char breakcheck(void) +{ +#ifdef __CONIO__ + if(kbhit()) + //return getch() == CTRLC; + return getc(0) == CTRLC; + else +#endif + return 0; +} +/***********************************************************/ +static int inchar() +{ + int v; + // otherwise. desktop! + // int got = getchar(); + int got = getc(0); + + // translation for desktop systems + if( got == LF ) got = CR; + + return got; +} + +/***********************************************************/ +/* +static void outchar(unsigned char c) +{ + if( inhibitOutput ) return; + + putchar(c); +} +*/ + + + + + +/* these are used in the .ino */ + +void outchar( char ch ) +{ + printf( "%c", ch ); +} + + +/* other helpers */ + +/* +int cmd_Files( void ) +{ + DIR * theDir; + + theDir = opendir( "." ); + if( !theDir ) return -2; + + struct dirent *theDirEnt = readdir( theDir ); + while( theDirEnt ) { + printf( " %s\n", theDirEnt->d_name ); + theDirEnt = readdir( theDir ); + } + closedir( theDir ); + + return 0; +} +*/ + + diff --git a/apps/shell/xsh_echo.c b/apps/shell/xsh_echo.c new file mode 100644 index 0000000..393c81a --- /dev/null +++ b/apps/shell/xsh_echo.c @@ -0,0 +1,24 @@ +/* xsh_echo.c - xsh_echo */ + +#include +#include + +/*------------------------------------------------------------------------ + * xhs_echo - write argument strings to stdout + *------------------------------------------------------------------------ + */ +shellcmd xsh_echo(int nargs, char *args[]) +{ + int32 i; /* walks through args array */ + + if (nargs > 1) { + printf("%s", args[1]); + + for (i = 2; i < nargs; i++) { + printf(" %s", args[i]); + } + } + printf("\n"); + + return 0; +} diff --git a/apps/shell/xsh_editor.c b/apps/shell/xsh_editor.c new file mode 100644 index 0000000..c6b5184 --- /dev/null +++ b/apps/shell/xsh_editor.c @@ -0,0 +1,101 @@ +/* xsh_editor.c - xsh_editor */ + +#include +#include + +// #include "text_buffer.h" +#define NLINES 3 +#define LINE_LEN 24 + +//extern unsigned char program[NLINES*LINE_LEN]; + +/*------------------------------------------------------------------------ + * xhs_editor - text editor + *------------------------------------------------------------------------ + */ +shellcmd xsh_editor(int nargs, char *args[]) +{ + +/* + int32 i; + + if (nargs > 1) { + printf("%s", args[1]); + + for (i = 2; i < nargs; i++) { + printf(" %s", args[i]); + } + } + printf("\n"); +*/ + char buffer[NLINES*LINE_LEN]; + int page = 0; + int i = 0; + int j = 0; + int dev = 0; + int c; + int cursor = 0; + int line = 0; + + fprintf(dev, "\033[2J"); + fprintf(dev, "\033[H"); + fprintf(dev, "Text editor. page: %i\n", page); + + for (i=0; i LINE_LEN) { + cursor = 0; + line++; + printf("\n\r"); + } + break; + default: + break; + } + } + continue; + } + + printf("%c", c); + buffer[line*LINE_LEN+cursor] = c; + cursor++; + if (cursor > LINE_LEN) { + cursor = 0; + line++; + printf("\n\r"); + if (line > NLINES) { + // pasar_pagina(); + } + } + + } + + + // RAFA + return 0; +} diff --git a/apps/shell/xsh_memstat.c b/apps/shell/xsh_memstat.c new file mode 100644 index 0000000..d94093b --- /dev/null +++ b/apps/shell/xsh_memstat.c @@ -0,0 +1,114 @@ +/* xsh_memstat.c - xsh_memstat */ + +#include +#include +#include + +// RAFA +#include + + +static void printMemUse(void); +static void printFreeList(void); + +/*------------------------------------------------------------------------ + * xsh_memstat - Print statistics about memory use and dump the free list + *------------------------------------------------------------------------ + */ +shellcmd xsh_memstat(int nargs, char *args[]) +{ + + +// printMemUse(); + printFreeList(); + + + return 0; +} + + +/*------------------------------------------------------------------------ + * printFreeList - Walk the list of free memory blocks and print the + * location and size of each + *------------------------------------------------------------------------ + */ +static void printFreeList(void) +{ +// char t[80]; + struct memblk *block; + + /* Output a heading for the free list */ + +// printf("Free:\n"); + printf("FreeMEM: addr len\n"); + + // avr_printf(m11); + for (block = memlist.mnext; block != NULL; block = block->mnext) { + printf("0x%08x %d\n", block, + (uint32) block->mlength); + } + long i; + int j=0; + char * c = 0; + for (i=0; i<0x5bd ; i++) { + c = (char *)i; + if (j==0) { + serial_put_char('\n'); + serial_put_char('\r'); + printf ("0x%08x ", c); + } + j++; + if (j==16) j=0; + if (*c < 33) + serial_put_char('-'); + else + serial_put_char(*c); + } +} + +extern void start(void); +extern void *_end; + +/*------------------------------------------------------------------------ + * printMemUse - Print statistics about memory use + *------------------------------------------------------------------------ + */ +static void printMemUse(void) +{ + int i; /* Index into process table */ + uint32 code = 0; /* Total Xinu code memory */ + uint32 stack = 0; /* Total used stack memory */ + uint32 kheap = 0; /* Free kernel heap memory */ + uint32 kfree = 0; /* Total free memory */ + struct memblk *block; /* Ptr to memory block */ + + /* Calculate amount of text memory */ + +// code = (uint32)&etext - (uint32)&text; + + /* Calculate amount of allocated stack memory */ + /* Skip the NULL process since it has a private stack */ + + for (i = 0; i < NPROC; i++) { + if (proctab[i].prstate != PR_FREE) { + stack += (uint32)proctab[i].prstklen; + } + } + + /* Calculate the amount of memory on the free list */ + + for (block = memlist.mnext; block != NULL; block = block->mnext) { + kfree += block->mlength; + } + + /* Calculate the amount of free kernel heap memory */ + + kheap = kfree - stack; + + /* Output statistics on current memory use */ + +// printf("code: %10d\n", (uint32) code); +// printf("stack:%10d bytes\n", (uint32) stack); +// printf("kernel stk:%10d bytes\n", (uint32) mspstack); +// printf("heap:%10d bytes\n\n", (uint32) kheap); +} diff --git a/include/shprototypes.h b/include/shprototypes.h index 5036eb6..8a1dfdd 100644 --- a/include/shprototypes.h +++ b/include/shprototypes.h @@ -29,7 +29,7 @@ extern shellcmd xsh_ethstat (int32, char *[]); extern shellcmd xsh_exit (int32, char *[]); /* in file xsh_help.c */ -extern shellcmd xsh_help (int32, char *[]); +// extern shellcmd xsh_help (int32, char *[]); /* in file xsh_kill.c */ extern shellcmd xsh_kill (int32, char *[]); @@ -74,7 +74,7 @@ extern shellcmd xsh_udpeserver (int32, char *[]); extern shellcmd xsh_uptime (int32, char *[]); /* in file xsh_help.c */ -extern shellcmd xsh_help (int32, char *[]); +// extern shellcmd xsh_help (int32, char *[]); // RAFA AGREGO TODO ESTO diff --git a/main/README b/main/README new file mode 100644 index 0000000..fc9b5b4 --- /dev/null +++ b/main/README @@ -0,0 +1,6 @@ + +This app needs the below modificationes into conf/Configuration file: + +#define NPROC 3 /* number of user processes */ +#define NSEM 2 /* number of semaphores */ + diff --git a/main/addargs.c b/main/addargs.c new file mode 100644 index 0000000..48580f6 --- /dev/null +++ b/main/addargs.c @@ -0,0 +1,119 @@ +/* addargs.c - addargs */ + +#include +#include "shprototypes.h" + +/*------------------------------------------------------------------------ + * addargs - Add local copy of argv-style arguments to the stack of + * a command process that has been created by the shell + *------------------------------------------------------------------------ + */ +status addargs( + pid32 pid, /* ID of process to use */ + int32 ntok, /* Count of arguments */ + int32 tok[], /* Index of tokens in tokbuf */ + int32 tlen, /* Length of data in tokbuf */ + char *tokbuf, /* Array of null-term. tokens */ + void *dummy /* Dummy argument that was */ + /* used at creation and must */ + /* be replaced by a pointer */ + /* to an argument vector */ + ) +{ + intmask mask; /* Saved interrupt mask */ + struct procent *prptr; /* Ptr to process' table entry */ + uint32 aloc; /* Argument location in process */ + /* stack as an integer */ + uint32 *argloc; /* Location in process's stack */ + /* to place args vector */ + char *argstr; /* Location in process's stack */ + /* to place arg strings */ + uint32 *search; /* pointer that searches for */ + /* dummy argument on stack */ + uint32 *aptr; /* Walks through args array */ + int32 i; /* Index into tok array */ + + mask = disable(); + + /* Check argument count and data length */ + + if ( (ntok <= 0) || (tlen < 0) ) { + // serial_put_char('M'); + restore(mask); + return SYSERR; + } + + prptr = &proctab[pid]; + + /* Compute lowest location in the process stack where the */ + /* args array will be stored followed by the argument */ + /* strings */ + +// aloc = (uint32) (prptr->prstkbase +// - prptr->prstklen + sizeof(uint32)); +// argloc = (uint32*) ((aloc + 3) & ~0x3); /* round multiple of 4 */ + + /* Compute the first location beyond args array for the strings */ +// +// argstr = (char *) (argloc + (ntok+1)); /* +1 for a null ptr */ + + /* Set each location in the args vector to be the address of */ + /* string area plus the offset of this argument */ + +// for (aptr=argloc, i=0; i < ntok; i++) { +// *aptr++ = (uint32) (argstr + tok[i]); +// } + + /* Add a null pointer to the args array */ + +// *aptr++ = (uint32)NULL; + + /* Copy the argument strings from tokbuf into process's stack */ + /* just beyond the args vector */ + +// memcpy(aptr, tokbuf, tlen); + + /* Find the second argument in process's stack */ + +// for (search = (uint32 *)prptr->prstkptr; +// search < (uint32 *)prptr->prstkbase; search++) { + + /* If found, replace with the address of the args vector*/ + +// if (*search == (uint32)dummy) { +// *search = (uint32)argloc; +// restore(mask); +// return OK; +// } +// } + + /* Argument value not found on the stack - report an error */ + + // serial_put_char('\n'); + +// for (fromarg=Shl.shtok ; nargs > 0 ; nargs--) { + for (i=0 ; i < ntok; i++) { + // prptr->parg[i+prptr->pargs] = (int)tok[i]; /******** change int parg[] TO void *parg[] in proc.h ******/ + // prptr->parg[i+prptr->pargs] = (void *)tok[i]; /******** change int parg[] TO void *parg[] in proc.h ******/ +// serial_put_char(48+i); +// serial_put_char(' '); +// serial_put_char(tokbuf[tok[i]]); +// serial_put_char(' '); + prptr->parg[i] = &tokbuf[tok[i]]; + + } +// *toarg = 0; + prptr->pargs = ntok; + prptr->parg[ntok] = 0; + +// RAFA prptr->pargs += ntok; +// RAFA prptr->parg[prptr->pargs] = 0; + /* machine/compiler dependent pass arguments to created process */ + prptr->pregs[24] = lobyte((unsigned)prptr->pargs); /*r24*/ + prptr->pregs[25] = hibyte((unsigned)prptr->pargs); + + + restore(mask); + return OK; +// return SYSERR; +} diff --git a/main/lexan.c b/main/lexan.c new file mode 100644 index 0000000..4e0cb8b --- /dev/null +++ b/main/lexan.c @@ -0,0 +1,148 @@ +/* lexan.c - lexan */ + +#include + +/*------------------------------------------------------------------------ + * lexan - Ad hoc lexical analyzer to divide command line into tokens + *------------------------------------------------------------------------ + */ + +int32 lexan ( + char *line, /* Input line terminated with */ + /* NEWLINE or NULLCH */ + int32 len, /* Length of the input line, */ + /* including NEWLINE */ + char *tokbuf, /* Buffer into which tokens are */ + /* stored with a null */ + /* following each token */ + int32 *tlen, /* Place to store number of */ + /* chars in tokbuf */ + int32 tok[], /* Array of pointers to the */ + /* start of each token */ + int32 toktyp[] /* Array that gives the type */ + /* of each token */ + ) +{ + char quote; /* Character for quoted string */ + uint32 ntok; /* Number of tokens found */ + char *p; /* Pointer that walks along the */ + /* input line */ + int32 tbindex; /* Index into tokbuf */ + char ch; /* Next char from input line */ + + /* Start at the beginning of the line with no tokens */ + + ntok = 0; + p = line; + tbindex = 0; + + /* While not yet at end of line, get next token */ + + while ( (*p != NULLCH) && (*p != SH_NEWLINE) ) { + + /* If too many tokens, return error */ + + if (ntok >= SHELL_MAXTOK) { + return SYSERR; + } + + /* Skip whitespace before token */ + + while ( (*p == SH_BLANK) || (*p == SH_TAB) ) { + p++; + } + + /* Stop parsing at end of line (or end of string) */ + + ch = *p; + if ( (ch==SH_NEWLINE) || (ch==NULLCH) ) { + *tlen = tbindex; + return ntok; + } + + /* Set next entry in tok array to be an index to the */ + /* current location in the token buffer */ + + tok[ntok] = tbindex; /* the start of the token */ + + /* Set the token type */ + + switch (ch) { + + case SH_AMPER: toktyp[ntok] = SH_TOK_AMPER; + tokbuf[tbindex++] = ch; + tokbuf[tbindex++] = NULLCH; + ntok++; + p++; + continue; + + case SH_LESS: toktyp[ntok] = SH_TOK_LESS; + tokbuf[tbindex++] = ch; + tokbuf[tbindex++] = NULLCH; + ntok++; + p++; + continue; + + case SH_GREATER: toktyp[ntok] = SH_TOK_GREATER; + tokbuf[tbindex++] = ch; + tokbuf[tbindex++] = NULLCH; + ntok++; + p++; + continue; + + default: toktyp[ntok] = SH_TOK_OTHER; + }; + + /* Handle quoted string (single or double quote) */ + + if ( (ch==SH_SQUOTE) || (ch==SH_DQUOTE) ) { + quote = ch; /* remember opening quote */ + + /* Copy quoted string to arg area */ + + p++; /* Move past starting quote */ + + while ( ((ch=*p++) != quote) && (ch != SH_NEWLINE) + && (ch != NULLCH) ) { + tokbuf[tbindex++] = ch; + } + if (ch != quote) { /* string missing end quote */ + return SYSERR; + } + + /* Finished string - count token and go on */ + + tokbuf[tbindex++] = NULLCH; /* terminate token */ + ntok++; /* count string as one token */ + continue; /* go to next token */ + } + + /* Handle a token other than a quoted string */ + + tokbuf[tbindex++] = ch; /* put first character in buffer*/ + p++; + + while ( ((ch = *p) != SH_NEWLINE) && (ch != NULLCH) + && (ch != SH_LESS) && (ch != SH_GREATER) + && (ch != SH_BLANK) && (ch != SH_TAB) + && (ch != SH_AMPER) && (ch != SH_SQUOTE) + && (ch != SH_DQUOTE) ) { + tokbuf[tbindex++] = ch; + p++; + } + + /* Report error if other token is appended */ + + if ( (ch == SH_SQUOTE) || (ch == SH_DQUOTE) + || (ch == SH_LESS) || (ch == SH_GREATER) ) { + return SYSERR; + } + + tokbuf[tbindex++] = NULLCH; /* terminate the token */ + + ntok++; /* count valid token */ + + } + *tlen = tbindex; + return ntok; +} diff --git a/main/main.c b/main/main.c new file mode 100644 index 0000000..7ea271b --- /dev/null +++ b/main/main.c @@ -0,0 +1,343 @@ +/* main.c - main */ + +/* shell.c - shell */ + + +#include +//#include +#include "shprototypes.h" + +void xsh_help(void) +{ + int i; + + printf("\n\rCommands:\n\n\r"); + for (i=0; i output_file */ +/* */ +/************************************************************************/ + +process main(void) +{ + char buf[SHELL_BUFLEN]; /* Input line (large enough for */ + int32 len; /* Length of line read */ + char tokbuf[SHELL_BUFLEN + /* Buffer to hold a set of */ + SHELL_MAXTOK]; /* Contiguous null-terminated */ + int32 tlen; /* Current length of all data */ + /* in array tokbuf */ + int32 tok[SHELL_MAXTOK]; /* Index of each token in */ + int32 toktyp[SHELL_MAXTOK]; /* Type of each token in tokbuf */ + int32 ntok; /* Number of tokens on line */ + pid32 child; /* Process ID of spawned child */ + bool8 backgnd; /* Run command in background? */ + char *outname, *inname; /* Pointers to strings for file */ + /* names that follow > and < */ + did32 stdinput, stdoutput; /* Descriptors for redirected */ + /* input and output */ + int32 i; /* Index into array of tokens */ + int32 j; /* Index into array of commands */ + int32 msg; /* Message from receive() for */ + /* child termination */ + int32 tmparg; /* Address of this var is used */ + /* when first creating child */ + /* process, but is replaced */ + char *src, *cmp; /* Pointers used during name */ + /* comparison */ + bool8 diff; /* Was difference found during */ + char *args[SHELL_MAXTOK]; /* Argument vector passed to */ + /* builtin commands */ + did32 dev = 0; /* ID of tty device from which */ + + /* Print shell banner and startup message */ + +/* + fprintf(dev, "\n\n%s%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", + SHELL_BAN0,SHELL_BAN1,SHELL_BAN2,SHELL_BAN3,SHELL_BAN4, + SHELL_BAN5,SHELL_BAN6,SHELL_BAN7,SHELL_BAN8,SHELL_BAN9,SHELL_BAN10); + + fprintf(dev, "%s\n\n", SHELL_STRTMSG); +*/ + + /* Continually prompt the user, read input, and execute command */ + + + while (TRUE) { + + // RAFA + // fprintf(dev, "\033[2J"); + // fprintf(dev, "\033[H"); + + /* Display prompt */ + fprintf(dev, SHELL_PROMPT); + + + len = read(dev, buf, sizeof(buf)); + + /* Exit gracefully on end-of-file */ + + if (len == EOF) { + break; + } + + /* If line contains only NEWLINE, go to next line */ + + if (len <= 1) { + continue; + } + + buf[len] = SH_NEWLINE; /* terminate line */ + + /* Parse input line and divide into tokens */ + + ntok = lexan(buf, len, tokbuf, &tlen, tok, toktyp); + + /* Handle parsing error */ + + if (ntok == SYSERR) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + + /* If line is empty, go to next input line */ + + if (ntok == 0) { + // fprintf(dev, "\n"); + continue; + } + + /* If last token is '&', set background */ + + if (toktyp[ntok-1] == SH_TOK_AMPER) { + ntok-- ; + tlen-= 2; + backgnd = TRUE; + } else { + backgnd = FALSE; + } + + + /* Check for input/output redirection (default is none) */ + + outname = inname = NULL; + if ( (ntok >=3) && ( (toktyp[ntok-2] == SH_TOK_LESS) + ||(toktyp[ntok-2] == SH_TOK_GREATER))){ + if (toktyp[ntok-1] != SH_TOK_OTHER) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + if (toktyp[ntok-2] == SH_TOK_LESS) { + inname = &tokbuf[tok[ntok-1]]; + } else { + outname = &tokbuf[tok[ntok-1]]; + } + ntok -= 2; + tlen = tok[ntok]; + } + + + if ( (ntok >=3) && ( (toktyp[ntok-2] == SH_TOK_LESS) + ||(toktyp[ntok-2] == SH_TOK_GREATER))){ + if (toktyp[ntok-1] != SH_TOK_OTHER) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + if (toktyp[ntok-2] == SH_TOK_LESS) { + if (inname != NULL) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + inname = &tokbuf[tok[ntok-1]]; + } else { + if (outname != NULL) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + outname = &tokbuf[tok[ntok-1]]; + } + ntok -= 2; + tlen = tok[ntok]; + } + + /* Verify remaining tokens are type "other" */ + + for (i=0; i= ncmd) { + // fprintf(dev, "command %s not found\n", tokbuf); + continue; + } + + /* Handle built-in command */ + + if (cmdtab[j].cbuiltin) { /* No background or redirect. */ + if (inname != NULL || outname != NULL || backgnd){ + // fprintf(dev, SHELL_BGERRMSG); + continue; + } else { + /* Set up arg vector for call */ + + for (i=0; i +#include + +#define NLINES 10 +#define LINE_LEN 24 + +void outchar( char ch ); + +#ifndef boolean + #define boolean int + #define true 1 + #define false 0 +#endif + + +#include "text_buffer.h" + +/*------------------------------------------------------------------------ + * xhs_editor - text editor + *------------------------------------------------------------------------ + */ +shellcmd xsh_basic(int nargs, char *args[]) +{ + + int dev = 0; + +// printf("stk: 0x%08x\n", &dev); + + control(dev, TC_MODER, 0, 0); + + setup(); + loop(); + + control(dev, TC_MODEC, 0, 0); + +// printf("stk: 0x%08x\n", &dev); + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +// TinyBasic Plus +//////////////////////////////////////////////////////////////////////////////// +// +// Authors: +// Gordon Brandly (Tiny Basic for 68000) +// Mike Field (Arduino Basic) (port to Arduino) +// Scott Lawrence (TinyBasic Plus) (features, etc) +// +// Contributors: +// Brian O'Dell (INPUT) +// (full list tbd) + +// For full history of Tiny Basic, please see the wikipedia entry here: +// https://en.wikipedia.org/wiki/Tiny_BASIC + +// LICENSING NOTES: +// Mike Field based his C port of Tiny Basic on the 68000 +// Tiny BASIC which carried the following license: +/* +****************************************************************** +* * +* Tiny BASIC for the Motorola MC68000 * +* * +* Derived from Palo Alto Tiny BASIC as published in the May 1976 * +* issue of Dr. Dobb's Journal. Adapted to the 68000 by: * +* Gordon Brandly * +* 12147 - 51 Street * +* Edmonton AB T5W 3G8 * +* Canada * +* (updated mailing address for 1996) * +* * +* This version is for MEX68KECB Educational Computer Board I/O. * +* * +****************************************************************** +* Copyright (C) 1984 by Gordon Brandly. This program may be * +* freely distributed for personal use only. All commercial * +* rights are reserved. * +****************************************************************** +*/ +// ref: http://members.shaw.ca:80/gbrandly/68ktinyb.html +// +// However, Mike did not include a license of his own for his +// version of this. +// ref: http://hamsterworks.co.nz/mediawiki/index.php/Arduino_Basic +// +// From discussions with him, I felt that the MIT license is +// the most applicable to his intent. +// +// I am in the process of further determining what should be +// done wrt licensing further. This entire header will likely +// change with the next version 0.16, which will hopefully nail +// down the whole thing so we can get back to implementing +// features instead of licenses. Thank you for your time. + +#define kVersion "v0.15" + +// v0.15: 2018-06-23 +// Integrating some contributions +// Corrected some of the #ifdef nesting atop this page +// Licensing issues beginning to be addressed + +// v0.14: 2013-11-07 +// Modified Input command to accept an expression using getn() +// Syntax is "input x" where x is any variable +// NOTE: This only works for numbers, expressions. not strings. +// +// v0.13: 2013-03-04 +// Support for Arduino 1.5 (SPI.h included, additional changes for DUE support) +// +// v0.12: 2013-03-01 +// EEPROM load and save routines added: EFORMAT, ELIST, ELOAD, ESAVE, ECHAIN +// added EAUTORUN option (chains to EEProm saved program on startup) +// Bugfixes to build properly on non-arduino systems (PROGMEM #define workaround) +// cleaned up a bit of the #define options wrt TONE +// +// v0.11: 2013-02-20 +// all display strings and tables moved to PROGMEM to save space +// removed second serial +// removed pinMode completely, autoconf is explicit +// beginnings of EEPROM related functionality (new,load,save,list) +// +// v0.10: 2012-10-15 +// added kAutoConf, which eliminates the "PINMODE" statement. +// now, DWRITE,DREAD,AWRITE,AREAD automatically set the PINMODE appropriately themselves. +// should save a few bytes in your programs. +// +// v0.09: 2012-10-12 +// Fixed directory listings. FILES now always works. (bug in the SD library) +// ref: http://arduino.cc/forum/index.php/topic,124739.0.html +// fixed filesize printouts (added printUnum for unsigned numbers) +// #defineable baud rate for slow connection throttling +//e +// v0.08: 2012-10-02 +// Tone generation through piezo added (TONE, TONEW, NOTONE) +// +// v0.07: 2012-09-30 +// Autorun buildtime configuration feature +// +// v0.06: 2012-09-27 +// Added optional second serial input, used for an external keyboard +// +// v0.05: 2012-09-21 +// CHAIN to load and run a second file +// RND,RSEED for random stuff +// Added "!=" for "<>" synonym +// Added "END" for "STOP" synonym (proper name for the functionality anyway) +// +// v0.04: 2012-09-20 +// DELAY ms - for delaying +// PINMODE , INPUT|IN|I|OUTPUT|OUT|O +// DWRITE , HIGH|HI|1|LOW|LO|0 +// AWRITE , [0..255] +// fixed "save" appending to existing files instead of overwriting +// Updated for building desktop command line app (incomplete) +// +// v0.03: 2012-09-19 +// Integrated Jurg Wullschleger whitespace,unary fix +// Now available through github +// Project renamed from "Tiny Basic in C" to "TinyBasic Plus" +// +// v0.02b: 2012-09-17 Scott Lawrence +// Better FILES listings +// +// v0.02a: 2012-09-17 Scott Lawrence +// Support for SD Library +// Added: SAVE, FILES (mostly works), LOAD (mostly works) (redirects IO) +// Added: MEM, ? (PRINT) +// Quirk: "10 LET A=B+C" is ok "10 LET A = B + C" is not. +// Quirk: INPUT seems broken? + +// IF testing with Visual C, this needs to be the first thing in the file. +//#include "stdafx.h" + +// char eliminateCompileErrors = 1; // fix to suppress arduino build errors + +// hack to let makefiles work with this file unchanged +#undef ARDUINO + + +//////////////////////////////////////////////////////////////////////////////// +// Feature option configuration... + +// This enables LOAD, SAVE, FILES commands through the Arduino SD Library +// it adds 9k of usage as well. +//#define ENABLE_FILEIO 1 +#undef ENABLE_FILEIO + +// this turns on "autorun". if there's FileIO, and a file "autorun.bas", +// then it will load it and run it when starting up +//#define ENABLE_AUTORUN 1 +#undef ENABLE_AUTORUN + +// this will enable the "TONE", "NOTONE" command using a piezo +// element on the specified pin. Wire the red/positive/piezo to the kPiezoPin, +// and the black/negative/metal disc to ground. +// it adds 1.5k of usage as well. +//#define ENABLE_TONES 1 +#define kPiezoPin 5 + +// we can use the EEProm to store a program during powerdown. This is +// 1kbyte on the '328, and 512 bytes on the '168. Enabling this here will +// allow for this funcitonality to work. Note that this only works on AVR +// arduino. Disable it for DUE/other devices. + +// Sometimes, we connect with a slower device as the console. +// Set your console D0/D1 baud rate here (9600 baud default) +#define kConsoleBaud 9600 + + + +// Enable memory alignment for certain processers (e.g. some ESP8266-based devices) +#ifdef ESP8266 + // Uses up to one extra byte per program line of memory + #define ALIGN_MEMORY 1 +#else + #undef ALIGN_MEMORY +#endif + + // not an arduino, so we can disable these features. + // turn off EEProm +#undef ENABLE_EEPROM +#undef ENABLE_TONES + + +// includes, and settings for Arduino-specific features + + +// set up file includes for things we need, or desktop specific stuff. + +#include +#include + +// size of our program ram +// RAFA #define kRamSize 64*1024 /* arbitrary - not dependant on libraries */ +// RAFA #define kRamSize 24 /* arbitrary - not dependant on libraries */ + + +// RAFA AGREGA +// #define ALIGN_MEMORY 1 + +//////////////////// + +// memory alignment +// necessary for some esp8266-based devices +#ifdef ALIGN_MEMORY + // Align memory addess x to an even page + #define ALIGN_UP(x) ((unsigned char*)(((unsigned int)(x + 1) >> 1) << 1)) + #define ALIGN_DOWN(x) ((unsigned char*)(((unsigned int)x >> 1) << 1)) +#else + #define ALIGN_UP(x) x + #define ALIGN_DOWN(x) x +#endif + + +//////////////////// +// various other desktop-tweaks and such. + +#ifndef boolean + #define boolean int + #define true 1 + #define false 0 +#endif + +#ifndef byte + typedef unsigned char byte; +#endif + +// some catches for AVR based text string stuff... +#ifndef PROGMEM + #define PROGMEM +#endif + +#ifndef pgm_read_byte + #define pgm_read_byte( A ) *(A) +#endif + +//////////////////// + + +// some settings based things + +boolean inhibitOutput = false; +static boolean runAfterLoad = false; +static boolean triggerRun = false; + +// these will select, at runtime, where IO happens through for load/save +enum { + kStreamSerial = 0, + kStreamEEProm, + kStreamFile +}; +static unsigned char inStream = kStreamSerial; +static unsigned char outStream = kStreamSerial; + + +//////////////////////////////////////////////////////////////////////////////// +// ASCII Characters +#define CR '\r' +#define NL '\n' +#define LF 0x0a +#define TAB '\t' +#define BELL '\b' +#define SPACE ' ' +#define SQUOTE '\'' +#define DQUOTE '\"' +#define CTRLC 0x03 +#define CTRLH 0x08 +#define CTRLS 0x13 +#define CTRLX 0x18 + +typedef short unsigned LINENUM; +#define ECHO_CHARS 0 + +// RAFA +//unsigned char program[kRamSize]; +// extern unsigned char program[NLINES*LINE_LEN]; + +static const char * sentinel = "HELLO"; +static unsigned char *txtpos,*list_line, *tmptxtpos; +static unsigned char expression_error; +static unsigned char *tempsp; + +/***********************************************************/ +// Keyword table and constants - the last character has 0x80 added to it +const static unsigned char keywords[] PROGMEM = { + 'L','I','S','T'+0x80, + 'L','O','A','D'+0x80, + 'N','E','W'+0x80, + 'R','U','N'+0x80, + 'S','A','V','E'+0x80, + 'N','E','X','T'+0x80, + 'L','E','T'+0x80, + 'I','F'+0x80, + 'G','O','T','O'+0x80, + 'G','O','S','U','B'+0x80, + 'R','E','T','U','R','N'+0x80, + 'R','E','M'+0x80, + 'F','O','R'+0x80, + 'I','N','P','U','T'+0x80, + 'P','R','I','N','T'+0x80, + 'P','O','K','E'+0x80, + 'S','T','O','P'+0x80, + 'B','Y','E'+0x80, + 'F','I','L','E','S'+0x80, + 'M','E','M'+0x80, + '?'+ 0x80, + '\''+ 0x80, + 'A','W','R','I','T','E'+0x80, + 'D','W','R','I','T','E'+0x80, + 'D','E','L','A','Y'+0x80, + 'E','N','D'+0x80, + 'R','S','E','E','D'+0x80, + 'C','H','A','I','N'+0x80, +#ifdef ENABLE_TONES + 'T','O','N','E','W'+0x80, + 'T','O','N','E'+0x80, + 'N','O','T','O','N','E'+0x80, +#endif + 0 +}; + +// by moving the command list to an enum, we can easily remove sections +// above and below simultaneously to selectively obliterate functionality. +enum { + KW_LIST = 0, + KW_LOAD, KW_NEW, KW_RUN, KW_SAVE, + KW_NEXT, KW_LET, KW_IF, + KW_GOTO, KW_GOSUB, KW_RETURN, + KW_REM, + KW_FOR, + KW_INPUT, KW_PRINT, + KW_POKE, + KW_STOP, KW_BYE, + KW_FILES, + KW_MEM, + KW_QMARK, KW_QUOTE, + KW_AWRITE, KW_DWRITE, + KW_DELAY, + KW_END, + KW_RSEED, + KW_CHAIN, +#ifdef ENABLE_TONES + KW_TONEW, KW_TONE, KW_NOTONE, +#endif + KW_DEFAULT /* always the final one*/ +}; + +struct stack_for_frame { + char frame_type; + char for_var; + short int terminal; + short int step; + unsigned char *current_line; + unsigned char *txtpos; +}; + +struct stack_gosub_frame { + char frame_type; + unsigned char *current_line; + unsigned char *txtpos; +}; + +const static unsigned char func_tab[] PROGMEM = { + 'P','E','E','K'+0x80, + 'A','B','S'+0x80, + 'A','R','E','A','D'+0x80, + 'D','R','E','A','D'+0x80, + 'R','N','D'+0x80, + 0 +}; +#define FUNC_PEEK 0 +#define FUNC_ABS 1 +#define FUNC_AREAD 2 +#define FUNC_DREAD 3 +#define FUNC_RND 4 +#define FUNC_UNKNOWN 5 + +const static unsigned char to_tab[] PROGMEM = { + 'T','O'+0x80, + 0 +}; + +const static unsigned char step_tab[] PROGMEM = { + 'S','T','E','P'+0x80, + 0 +}; + +const static unsigned char relop_tab[] PROGMEM = { + '>','='+0x80, + '<','>'+0x80, + '>'+0x80, + '='+0x80, + '<','='+0x80, + '<'+0x80, + '!','='+0x80, + 0 +}; + +#define RELOP_GE 0 +#define RELOP_NE 1 +#define RELOP_GT 2 +#define RELOP_EQ 3 +#define RELOP_LE 4 +#define RELOP_LT 5 +#define RELOP_NE_BANG 6 +#define RELOP_UNKNOWN 7 + +const static unsigned char highlow_tab[] PROGMEM = { + 'H','I','G','H'+0x80, + 'H','I'+0x80, + 'L','O','W'+0x80, + 'L','O'+0x80, + 0 +}; +#define HIGHLOW_HIGH 1 +#define HIGHLOW_UNKNOWN 4 + +//RAFA ANTES DECIA 5 +//#define STACK_SIZE (sizeof(struct stack_for_frame)*5) +#define STACK_SIZE (sizeof(struct stack_for_frame)*4) + + +#define VAR_SIZE sizeof(short int) // Size of variables in bytes + +static unsigned char *stack_limit; +static unsigned char *program_start; +static unsigned char *program_end; +// static unsigned char *stack; // Software stack for things that should go on the CPU stack +static unsigned char *variables_begin; +static unsigned char *current_line; +static unsigned char *sp; +#define STACK_GOSUB_FLAG 'G' +#define STACK_FOR_FLAG 'F' +static unsigned char table_index; +static LINENUM linenum; + +static const unsigned char okmsg[] PROGMEM = "OK"; +static const unsigned char whatmsg[] PROGMEM = "What? "; +static const unsigned char howmsg[] PROGMEM = "How?"; +static const unsigned char sorrymsg[] PROGMEM = "Sorry!"; +static const unsigned char initmsg[] PROGMEM = "TinyBasic Plus " kVersion; +static const unsigned char memorymsg[] PROGMEM = " bytes free."; +static const unsigned char breakmsg[] PROGMEM = "break!"; +static const unsigned char unimplimentedmsg[] PROGMEM = "Unimplemented"; +static const unsigned char backspacemsg[] PROGMEM = "\b \b"; +static const unsigned char indentmsg[] PROGMEM = " "; +static const unsigned char sderrormsg[] PROGMEM = "SD card error."; +static const unsigned char sdfilemsg[] PROGMEM = "SD file error."; +static const unsigned char dirextmsg[] PROGMEM = "(dir)"; +static const unsigned char slashmsg[] PROGMEM = "/"; +static const unsigned char spacemsg[] PROGMEM = " "; + +static int inchar(void); +//static void outchar(unsigned char c); +static void line_terminator(void); +static short int expression(void); +static unsigned char breakcheck(void); +/***************************************************************************/ +static void ignore_blanks(void) +{ + while(*txtpos == SPACE || *txtpos == TAB) + txtpos++; +} + + +/***************************************************************************/ +static void scantable(const unsigned char *table) +{ + int i = 0; + table_index = 0; + while(1) + { + // Run out of table entries? + if(pgm_read_byte( table ) == 0) + return; + + // Do we match this character? + if(txtpos[i] == pgm_read_byte( table )) + { + i++; + table++; + } + else + { + // do we match the last character of keywork (with 0x80 added)? If so, return + if(txtpos[i]+0x80 == pgm_read_byte( table )) + { + txtpos += i+1; // Advance the pointer to following the keyword + ignore_blanks(); + return; + } + + // Forward to the end of this keyword + while((pgm_read_byte( table ) & 0x80) == 0) + table++; + + // Now move on to the first character of the next word, and reset the position index + table++; + table_index++; + ignore_blanks(); + i = 0; + } + } +} + +/***************************************************************************/ +static void pushb(unsigned char b) +{ + sp--; + *sp = b; +} + +/***************************************************************************/ +static unsigned char popb() +{ + unsigned char b; + b = *sp; + sp++; + return b; +} + +/***************************************************************************/ +void printnum(int num) +{ + int digits = 0; + + if(num < 0) + { + num = -num; + outchar('-'); + } + do { + pushb(num%10+'0'); + num = num/10; + digits++; + } + while (num > 0); + + while(digits > 0) + { + outchar(popb()); + digits--; + } +} + +void printUnum(unsigned int num) +{ + int digits = 0; + + do { + pushb(num%10+'0'); + num = num/10; + digits++; + } + while (num > 0); + + while(digits > 0) + { + outchar(popb()); + digits--; + } +} + +/***************************************************************************/ +static unsigned short testnum(void) +{ + unsigned short num = 0; + ignore_blanks(); + + while(*txtpos>= '0' && *txtpos <= '9' ) + { + // Trap overflows + if(num >= 0xFFFF/10) + { + num = 0xFFFF; + break; + } + + num = num *10 + *txtpos - '0'; + txtpos++; + } + return num; +} + +/***************************************************************************/ +static unsigned char print_quoted_string(void) +{ + int i=0; + unsigned char delim = *txtpos; + if(delim != '"' && delim != '\'') + return 0; + txtpos++; + + // Check we have a closing delimiter + while(txtpos[i] != delim) + { + if(txtpos[i] == NL) + return 0; + i++; + } + + // Print the characters + while(*txtpos != delim) + { + outchar(*txtpos); + txtpos++; + } + txtpos++; // Skip over the last delimiter + + return 1; +} + + +/***************************************************************************/ +void printmsgNoNL(const unsigned char *msg) +{ + while( pgm_read_byte( msg ) != 0 ) { + outchar( pgm_read_byte( msg++ ) ); + }; +} + +/***************************************************************************/ +void printmsg(const unsigned char *msg) +{ + printmsgNoNL(msg); + line_terminator(); +} + +/***************************************************************************/ +static void getln(char prompt) +{ + char s = ' '; + outchar(prompt); + outchar(s); + txtpos = program_end+sizeof(LINENUM); + + while(1) + { + char c = inchar(); + switch(c) + { + case NL: + //break; + case CR: + line_terminator(); + // Terminate all strings with a NL + txtpos[0] = NL; + return; + case CTRLH: + if(txtpos == program_end) + break; + txtpos--; + + printmsg(backspacemsg); + break; + default: + // We need to leave at least one space to allow us to shuffle the line into order + if(txtpos == variables_begin-2) + outchar(BELL); + else + { + txtpos[0] = c; + txtpos++; + outchar(c); + } + } + } +} + +/***************************************************************************/ +static unsigned char *findline(void) +{ + unsigned char *line = program_start; + while(1) + { + if(line == program_end) + return line; + + if(((LINENUM *)line)[0] >= linenum) + return line; + + // Add the line length onto the current address, to get to the next line; + line += line[sizeof(LINENUM)]; + } +} + +/***************************************************************************/ +static void toUppercaseBuffer(void) +{ + unsigned char *c = program_end+sizeof(LINENUM); + unsigned char quote = 0; + + while(*c != NL) + { + // Are we in a quoted string? + if(*c == quote) + quote = 0; + else if(*c == '"' || *c == '\'') + quote = *c; + else if(quote == 0 && *c >= 'a' && *c <= 'z') + *c = *c + 'A' - 'a'; + c++; + } +} + +/***************************************************************************/ +void printline() +{ + LINENUM line_num; + + line_num = *((LINENUM *)(list_line)); + list_line += sizeof(LINENUM) + sizeof(char); + + // Output the line */ + printnum(line_num); + outchar(' '); + while(*list_line != NL) + { + outchar(*list_line); + list_line++; + } + list_line++; +#ifdef ALIGN_MEMORY + // Start looking for next line on even page + if (ALIGN_UP(list_line) != list_line) + list_line++; +#endif + line_terminator(); +} + +/***************************************************************************/ +static short int expr4(void) +{ + // fix provided by Jurg Wullschleger wullschleger@gmail.com + // fixes whitespace and unary operations + ignore_blanks(); + + if( *txtpos == '-' ) { + txtpos++; + return -expr4(); + } + // end fix + + if(*txtpos == '0') + { + txtpos++; + return 0; + } + + if(*txtpos >= '1' && *txtpos <= '9') + { + short int a = 0; + do { + a = a*10 + *txtpos - '0'; + txtpos++; + } + while(*txtpos >= '0' && *txtpos <= '9'); + return a; + } + + // Is it a function or variable reference? + if(txtpos[0] >= 'A' && txtpos[0] <= 'Z') + { + short int a; + // Is it a variable reference (single alpha) + if(txtpos[1] < 'A' || txtpos[1] > 'Z') + { + a = ((short int *)variables_begin)[*txtpos - 'A']; + txtpos++; + return a; + } + + // Is it a function with a single parameter + scantable(func_tab); + if(table_index == FUNC_UNKNOWN) + goto expr4_error; + + unsigned char f = table_index; + + if(*txtpos != '(') + goto expr4_error; + + txtpos++; + a = expression(); + if(*txtpos != ')') + goto expr4_error; + txtpos++; + switch(f) + { + case FUNC_PEEK: +// RAFA return program[a]; + return 0; + + case FUNC_ABS: + if(a < 0) + return -a; + return a; + + + case FUNC_RND: + return( rand() % a ); + } + } + + if(*txtpos == '(') + { + short int a; + txtpos++; + a = expression(); + if(*txtpos != ')') + goto expr4_error; + + txtpos++; + return a; + } + +expr4_error: + expression_error = 1; + return 0; + +} + +/***************************************************************************/ +static short int expr3(void) +{ + short int a,b; + + a = expr4(); + + ignore_blanks(); // fix for eg: 100 a = a + 1 + + while(1) + { + if(*txtpos == '*') + { + txtpos++; + b = expr4(); + a *= b; + } + else if(*txtpos == '/') + { + txtpos++; + b = expr4(); + if(b != 0) + a /= b; + else + expression_error = 1; + } + else + return a; + } +} + +/***************************************************************************/ +static short int expr2(void) +{ + short int a,b; + + if(*txtpos == '-' || *txtpos == '+') + a = 0; + else + a = expr3(); + + while(1) + { + if(*txtpos == '-') + { + txtpos++; + b = expr3(); + a -= b; + } + else if(*txtpos == '+') + { + txtpos++; + b = expr3(); + a += b; + } + else + return a; + } +} +/***************************************************************************/ +static short int expression(void) +{ + short int a,b; + + a = expr2(); + + // Check if we have an error + if(expression_error) return a; + + scantable(relop_tab); + if(table_index == RELOP_UNKNOWN) + return a; + + switch(table_index) + { + case RELOP_GE: + b = expr2(); + if(a >= b) return 1; + break; + case RELOP_NE: + case RELOP_NE_BANG: + b = expr2(); + if(a != b) return 1; + break; + case RELOP_GT: + b = expr2(); + if(a > b) return 1; + break; + case RELOP_EQ: + b = expr2(); + if(a == b) return 1; + break; + case RELOP_LE: + b = expr2(); + if(a <= b) return 1; + break; + case RELOP_LT: + b = expr2(); + if(a < b) return 1; + break; + } + return 0; +} + +/***************************************************************************/ +void loop() +{ + unsigned char *start; + unsigned char *newEnd; + unsigned char linelen; + boolean isDigital; + boolean alsoWait = false; + int val; + + unsigned char program[NLINES*LINE_LEN]; + + program_start = program; + program_end = program_start; + sp = program+sizeof(program); // Needed for printnum +#ifdef ALIGN_MEMORY + // Ensure these memory blocks start on even pages + stack_limit = ALIGN_DOWN(program+sizeof(program)-STACK_SIZE); + variables_begin = ALIGN_DOWN(stack_limit - 27*VAR_SIZE); +#else + stack_limit = program+sizeof(program)-STACK_SIZE; + variables_begin = stack_limit - 27*VAR_SIZE; +#endif + + // memory free + printnum(variables_begin-program_end); + printmsg(memorymsg); + +warmstart: + // this signifies that it is running in 'direct' mode. + current_line = 0; + sp = program+sizeof(program); + printmsg(okmsg); + +prompt: + if( triggerRun ){ + triggerRun = false; + current_line = program_start; + goto execline; + } + + getln( '>' ); + toUppercaseBuffer(); + + txtpos = program_end+sizeof(unsigned short); + + // Find the end of the freshly entered line + while(*txtpos != NL) + txtpos++; + + // Move it to the end of program_memory + { + unsigned char *dest; + dest = variables_begin-1; + while(1) + { + *dest = *txtpos; + if(txtpos == program_end+sizeof(unsigned short)) + break; + dest--; + txtpos--; + } + txtpos = dest; + } + + // Now see if we have a line number + linenum = testnum(); + ignore_blanks(); + if(linenum == 0) + goto direct; + + if(linenum == 0xFFFF) + goto qhow; + + // Find the length of what is left, including the (yet-to-be-populated) line header + linelen = 0; + while(txtpos[linelen] != NL) + linelen++; + linelen++; // Include the NL in the line length + linelen += sizeof(unsigned short)+sizeof(char); // Add space for the line number and line length + + // Now we have the number, add the line header. + txtpos -= 3; + +#ifdef ALIGN_MEMORY + // Line starts should always be on 16-bit pages + if (ALIGN_DOWN(txtpos) != txtpos) + { + txtpos--; + linelen++; + // As the start of the line has moved, the data should move as well + unsigned char *tomove; + tomove = txtpos + 3; + while (tomove < txtpos + linelen - 1) + { + *tomove = *(tomove + 1); + tomove++; + } + } +#endif + + *((unsigned short *)txtpos) = linenum; + txtpos[sizeof(LINENUM)] = linelen; + + + // Merge it into the rest of the program + start = findline(); + + // If a line with that number exists, then remove it + if(start != program_end && *((LINENUM *)start) == linenum) + { + unsigned char *dest, *from; + unsigned tomove; + + from = start + start[sizeof(LINENUM)]; + dest = start; + + tomove = program_end - from; + while( tomove > 0) + { + *dest = *from; + from++; + dest++; + tomove--; + } + program_end = dest; + } + + if(txtpos[sizeof(LINENUM)+sizeof(char)] == NL) // If the line has no txt, it was just a delete + goto prompt; + + + + // Make room for the new line, either all in one hit or lots of little shuffles + while(linelen > 0) + { + unsigned int tomove; + unsigned char *from,*dest; + unsigned int space_to_make; + + space_to_make = txtpos - program_end; + + if(space_to_make > linelen) + space_to_make = linelen; + newEnd = program_end+space_to_make; + tomove = program_end - start; + + + // Source and destination - as these areas may overlap we need to move bottom up + from = program_end; + dest = newEnd; + while(tomove > 0) + { + from--; + dest--; + *dest = *from; + tomove--; + } + + // Copy over the bytes into the new space + for(tomove = 0; tomove < space_to_make; tomove++) + { + *start = *txtpos; + txtpos++; + start++; + linelen--; + } + program_end = newEnd; + } + goto prompt; + +unimplemented: + printmsg(unimplimentedmsg); + goto prompt; + +qhow: + printmsg(howmsg); + goto prompt; + +qwhat: + printmsgNoNL(whatmsg); + if(current_line != NULL) + { + unsigned char tmp = *txtpos; + if(*txtpos != NL) + *txtpos = '^'; + list_line = current_line; + printline(); + *txtpos = tmp; + } + line_terminator(); + goto prompt; + +qsorry: + printmsg(sorrymsg); + goto warmstart; + +run_next_statement: + while(*txtpos == ':') + txtpos++; + ignore_blanks(); + if(*txtpos == NL) + goto execnextline; + goto interperateAtTxtpos; + +direct: + txtpos = program_end+sizeof(LINENUM); + if(*txtpos == NL) + goto prompt; + +interperateAtTxtpos: + if(breakcheck()) + { + printmsg(breakmsg); + goto warmstart; + } + + scantable(keywords); + +// RAFA +// short int val; +// int stk2 = 4; + + switch(table_index) + { + case KW_DELAY: + { + goto unimplemented; + } + + case KW_FILES: + goto files; + case KW_LIST: + goto list; + case KW_CHAIN: + goto chain; + case KW_LOAD: + goto load; + case KW_MEM: + goto mem; + case KW_NEW: + if(txtpos[0] != NL) + goto qwhat; + program_end = program_start; + goto prompt; + case KW_RUN: + current_line = program_start; + goto execline; + case KW_SAVE: + goto save; + case KW_NEXT: + goto next; + case KW_LET: + goto assignment; + case KW_IF: + // short int val; + expression_error = 0; + val = expression(); + if(expression_error || *txtpos == NL) + goto qhow; + if(val != 0) + goto interperateAtTxtpos; + goto execnextline; + + case KW_GOTO: + expression_error = 0; + linenum = expression(); + if(expression_error || *txtpos != NL) + goto qhow; + current_line = findline(); + goto execline; + + case KW_GOSUB: + goto gosub; + case KW_RETURN: + goto gosub_return; + case KW_REM: + case KW_QUOTE: + goto execnextline; // Ignore line completely + case KW_FOR: + goto forloop; + case KW_INPUT: + goto input; + case KW_PRINT: + case KW_QMARK: + goto print; + case KW_POKE: + goto poke; + case KW_END: + case KW_STOP: + // This is the easy way to end - set the current line to the end of program attempt to run it + if(txtpos[0] != NL) + goto qwhat; + current_line = program_end; + goto execline; + case KW_BYE: +// printf("stk2: 0x%08x\n", &stk2); + // Leave the basic interperater + return; + + case KW_AWRITE: // AWRITE , HIGH|LOW + isDigital = false; + goto awrite; + case KW_DWRITE: // DWRITE , HIGH|LOW + isDigital = true; + goto dwrite; + + case KW_RSEED: + goto rseed; + +#ifdef ENABLE_TONES + case KW_TONEW: + alsoWait = true; + case KW_TONE: + goto tonegen; + case KW_NOTONE: + goto tonestop; +#endif + + + case KW_DEFAULT: + goto assignment; + default: + break; + } + +execnextline: + if(current_line == NULL) // Processing direct commands? + goto prompt; + current_line += current_line[sizeof(LINENUM)]; + +execline: + if(current_line == program_end) // Out of lines to run + goto warmstart; + txtpos = current_line+sizeof(LINENUM)+sizeof(char); + goto interperateAtTxtpos; + + +input: + { + unsigned char var; + int value; + ignore_blanks(); + if(*txtpos < 'A' || *txtpos > 'Z') + goto qwhat; + var = *txtpos; + txtpos++; + ignore_blanks(); + if(*txtpos != NL && *txtpos != ':') + goto qwhat; +inputagain: + tmptxtpos = txtpos; + getln( '?' ); + toUppercaseBuffer(); + txtpos = program_end+sizeof(unsigned short); + ignore_blanks(); + expression_error = 0; + value = expression(); + if(expression_error) + goto inputagain; + ((short int *)variables_begin)[var-'A'] = value; + txtpos = tmptxtpos; + + goto run_next_statement; + } + +forloop: + { + unsigned char var; + short int initial, step, terminal; + ignore_blanks(); + if(*txtpos < 'A' || *txtpos > 'Z') + goto qwhat; + var = *txtpos; + txtpos++; + ignore_blanks(); + if(*txtpos != '=') + goto qwhat; + txtpos++; + ignore_blanks(); + + expression_error = 0; + initial = expression(); + if(expression_error) + goto qwhat; + + scantable(to_tab); + if(table_index != 0) + goto qwhat; + + terminal = expression(); + if(expression_error) + goto qwhat; + + scantable(step_tab); + if(table_index == 0) + { + step = expression(); + if(expression_error) + goto qwhat; + } + else + step = 1; + ignore_blanks(); + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + + + if(!expression_error && *txtpos == NL) + { + struct stack_for_frame *f; + if(sp + sizeof(struct stack_for_frame) < stack_limit) + goto qsorry; + + sp -= sizeof(struct stack_for_frame); + f = (struct stack_for_frame *)sp; + ((short int *)variables_begin)[var-'A'] = initial; + f->frame_type = STACK_FOR_FLAG; + f->for_var = var; + f->terminal = terminal; + f->step = step; + f->txtpos = txtpos; + f->current_line = current_line; + goto run_next_statement; + } + } + goto qhow; + +gosub: + expression_error = 0; + linenum = expression(); + if(!expression_error && *txtpos == NL) + { + struct stack_gosub_frame *f; + if(sp + sizeof(struct stack_gosub_frame) < stack_limit) + goto qsorry; + + sp -= sizeof(struct stack_gosub_frame); + f = (struct stack_gosub_frame *)sp; + f->frame_type = STACK_GOSUB_FLAG; + f->txtpos = txtpos; + f->current_line = current_line; + current_line = findline(); + goto execline; + } + goto qhow; + +next: + // Fnd the variable name + ignore_blanks(); + if(*txtpos < 'A' || *txtpos > 'Z') + goto qhow; + txtpos++; + ignore_blanks(); + if(*txtpos != ':' && *txtpos != NL) + goto qwhat; + +gosub_return: + // Now walk up the stack frames and find the frame we want, if present + tempsp = sp; + while(tempsp < program+sizeof(program)-1) + { + switch(tempsp[0]) + { + case STACK_GOSUB_FLAG: + if(table_index == KW_RETURN) + { + struct stack_gosub_frame *f = (struct stack_gosub_frame *)tempsp; + current_line = f->current_line; + txtpos = f->txtpos; + sp += sizeof(struct stack_gosub_frame); + goto run_next_statement; + } + // This is not the loop you are looking for... so Walk back up the stack + tempsp += sizeof(struct stack_gosub_frame); + break; + case STACK_FOR_FLAG: + // Flag, Var, Final, Step + if(table_index == KW_NEXT) + { + struct stack_for_frame *f = (struct stack_for_frame *)tempsp; + // Is the the variable we are looking for? + if(txtpos[-1] == f->for_var) + { + short int *varaddr = ((short int *)variables_begin) + txtpos[-1] - 'A'; + *varaddr = *varaddr + f->step; + // Use a different test depending on the sign of the step increment + if((f->step > 0 && *varaddr <= f->terminal) || (f->step < 0 && *varaddr >= f->terminal)) + { + // We have to loop so don't pop the stack + txtpos = f->txtpos; + current_line = f->current_line; + goto run_next_statement; + } + // We've run to the end of the loop. drop out of the loop, popping the stack + sp = tempsp + sizeof(struct stack_for_frame); + goto run_next_statement; + } + } + // This is not the loop you are looking for... so Walk back up the stack + tempsp += sizeof(struct stack_for_frame); + break; + default: + //printf("Stack is stuffed!\n"); + goto warmstart; + } + } + // Didn't find the variable we've been looking for + goto qhow; + +assignment: + { + short int value; + short int *var; + + if(*txtpos < 'A' || *txtpos > 'Z') + goto qhow; + var = (short int *)variables_begin + *txtpos - 'A'; + txtpos++; + + ignore_blanks(); + + if (*txtpos != '=') + goto qwhat; + txtpos++; + ignore_blanks(); + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + // Check that we are at the end of the statement + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + *var = value; + } + goto run_next_statement; +poke: + { + short int value; + unsigned char *address; + + // Work out where to put it + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + address = (unsigned char *)value; + + // check for a comma + ignore_blanks(); + if (*txtpos != ',') + goto qwhat; + txtpos++; + ignore_blanks(); + + // Now get the value to assign + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + //printf("Poke %p value %i\n",address, (unsigned char)value); + // Check that we are at the end of the statement + if(*txtpos != NL && *txtpos != ':') + goto qwhat; + } + goto run_next_statement; + +list: + linenum = testnum(); // Retuns 0 if no line found. + + // Should be EOL + if(txtpos[0] != NL) + goto qwhat; + + // Find the line + list_line = findline(); + while(list_line != program_end) + printline(); + goto warmstart; + +print: + // If we have an empty list then just put out a NL + if(*txtpos == ':' ) + { + line_terminator(); + txtpos++; + goto run_next_statement; + } + if(*txtpos == NL) + { + goto execnextline; + } + + while(1) + { + ignore_blanks(); + if(print_quoted_string()) + { + ; + } + else if(*txtpos == '"' || *txtpos == '\'') + goto qwhat; + else + { + short int e; + expression_error = 0; + e = expression(); + if(expression_error) + goto qwhat; + printnum(e); + } + + // At this point we have three options, a comma or a new line + if(*txtpos == ',') + txtpos++; // Skip the comma and move onto the next + else if(txtpos[0] == ';' && (txtpos[1] == NL || txtpos[1] == ':')) + { + txtpos++; // This has to be the end of the print - no newline + break; + } + else if(*txtpos == NL || *txtpos == ':') + { + line_terminator(); // The end of the print statement + break; + } + else + goto qwhat; + } + goto run_next_statement; + +mem: + // memory free + printnum(variables_begin-program_end); + printmsg(memorymsg); + goto run_next_statement; + + + /*************************************************/ + +pinmode: // PINMODE , I/O +awrite: // AWRITE ,val +dwrite: + goto unimplemented; + + /*************************************************/ +files: + // display a listing of files on the device. + // version 1: no support for subdirectories + + goto unimplemented; + + +chain: + runAfterLoad = true; + +load: + // clear the program + program_end = program_start; + + // load from a file into memory + goto unimplemented; + + + +save: + // save from memory out to a file + goto unimplemented; + +rseed: + { + short int value; + + //Get the pin number + expression_error = 0; + value = expression(); + if(expression_error) + goto qwhat; + + srand( value ); + goto run_next_statement; + } + +#ifdef ENABLE_TONES +tonestop: + noTone( kPiezoPin ); + goto run_next_statement; + +tonegen: + { + // TONE freq, duration + // if either are 0, tones turned off + short int freq; + short int duration; + + //Get the frequency + expression_error = 0; + freq = expression(); + if(expression_error) + goto qwhat; + + ignore_blanks(); + if (*txtpos != ',') + goto qwhat; + txtpos++; + ignore_blanks(); + + + //Get the duration + expression_error = 0; + duration = expression(); + if(expression_error) + goto qwhat; + + if( freq == 0 || duration == 0 ) + goto tonestop; + + tone( kPiezoPin, freq, duration ); + if( alsoWait ) { + delay( duration ); + alsoWait = false; + } + goto run_next_statement; + } +#endif /* ENABLE_TONES */ +} + +// returns 1 if the character is valid in a filename +static int isValidFnChar( char c ) +{ + if( c >= '0' && c <= '9' ) return 1; // number + if( c >= 'A' && c <= 'Z' ) return 1; // LETTER + if( c >= 'a' && c <= 'z' ) return 1; // letter (for completeness) + if( c == '_' ) return 1; + if( c == '+' ) return 1; + if( c == '.' ) return 1; + if( c == '~' ) return 1; // Window~1.txt + + return 0; +} + +unsigned char * filenameWord(void) +{ + // SDL - I wasn't sure if this functionality existed above, so I figured i'd put it here + unsigned char * ret = txtpos; + expression_error = 0; + + // make sure there are no quotes or spaces, search for valid characters + //while(*txtpos == SPACE || *txtpos == TAB || *txtpos == SQUOTE || *txtpos == DQUOTE ) txtpos++; + while( !isValidFnChar( *txtpos )) txtpos++; + ret = txtpos; + + if( *ret == '\0' ) { + expression_error = 1; + return ret; + } + + // now, find the next nonfnchar + txtpos++; + while( isValidFnChar( *txtpos )) txtpos++; + if( txtpos != ret ) *txtpos = '\0'; + + // set the error code if we've got no string + if( *ret == '\0' ) { + expression_error = 1; + } + + return ret; +} + +/***************************************************************************/ +static void line_terminator(void) +{ + outchar(NL); + outchar(CR); +} + +/***********************************************************/ +void setup() +{ +} + + +/***********************************************************/ +static unsigned char breakcheck(void) +{ +#ifdef __CONIO__ + if(kbhit()) + //return getch() == CTRLC; + return getc(0) == CTRLC; + else +#endif + return 0; +} +/***********************************************************/ +static int inchar() +{ + int v; + // otherwise. desktop! + // int got = getchar(); + int got = getc(0); + + // translation for desktop systems + if( got == LF ) got = CR; + + return got; +} + +/***********************************************************/ +/* +static void outchar(unsigned char c) +{ + if( inhibitOutput ) return; + + putchar(c); +} +*/ + + + + + +/* these are used in the .ino */ + +void outchar( char ch ) +{ + printf( "%c", ch ); +} + + +/* other helpers */ + +/* +int cmd_Files( void ) +{ + DIR * theDir; + + theDir = opendir( "." ); + if( !theDir ) return -2; + + struct dirent *theDirEnt = readdir( theDir ); + while( theDirEnt ) { + printf( " %s\n", theDirEnt->d_name ); + theDirEnt = readdir( theDir ); + } + closedir( theDir ); + + return 0; +} +*/ + + diff --git a/main/xsh_echo.c b/main/xsh_echo.c new file mode 100644 index 0000000..393c81a --- /dev/null +++ b/main/xsh_echo.c @@ -0,0 +1,24 @@ +/* xsh_echo.c - xsh_echo */ + +#include +#include + +/*------------------------------------------------------------------------ + * xhs_echo - write argument strings to stdout + *------------------------------------------------------------------------ + */ +shellcmd xsh_echo(int nargs, char *args[]) +{ + int32 i; /* walks through args array */ + + if (nargs > 1) { + printf("%s", args[1]); + + for (i = 2; i < nargs; i++) { + printf(" %s", args[i]); + } + } + printf("\n"); + + return 0; +} diff --git a/main/xsh_editor.c b/main/xsh_editor.c new file mode 100644 index 0000000..c6b5184 --- /dev/null +++ b/main/xsh_editor.c @@ -0,0 +1,101 @@ +/* xsh_editor.c - xsh_editor */ + +#include +#include + +// #include "text_buffer.h" +#define NLINES 3 +#define LINE_LEN 24 + +//extern unsigned char program[NLINES*LINE_LEN]; + +/*------------------------------------------------------------------------ + * xhs_editor - text editor + *------------------------------------------------------------------------ + */ +shellcmd xsh_editor(int nargs, char *args[]) +{ + +/* + int32 i; + + if (nargs > 1) { + printf("%s", args[1]); + + for (i = 2; i < nargs; i++) { + printf(" %s", args[i]); + } + } + printf("\n"); +*/ + char buffer[NLINES*LINE_LEN]; + int page = 0; + int i = 0; + int j = 0; + int dev = 0; + int c; + int cursor = 0; + int line = 0; + + fprintf(dev, "\033[2J"); + fprintf(dev, "\033[H"); + fprintf(dev, "Text editor. page: %i\n", page); + + for (i=0; i LINE_LEN) { + cursor = 0; + line++; + printf("\n\r"); + } + break; + default: + break; + } + } + continue; + } + + printf("%c", c); + buffer[line*LINE_LEN+cursor] = c; + cursor++; + if (cursor > LINE_LEN) { + cursor = 0; + line++; + printf("\n\r"); + if (line > NLINES) { + // pasar_pagina(); + } + } + + } + + + // RAFA + return 0; +} diff --git a/main/xsh_memstat.c b/main/xsh_memstat.c new file mode 100644 index 0000000..d94093b --- /dev/null +++ b/main/xsh_memstat.c @@ -0,0 +1,114 @@ +/* xsh_memstat.c - xsh_memstat */ + +#include +#include +#include + +// RAFA +#include + + +static void printMemUse(void); +static void printFreeList(void); + +/*------------------------------------------------------------------------ + * xsh_memstat - Print statistics about memory use and dump the free list + *------------------------------------------------------------------------ + */ +shellcmd xsh_memstat(int nargs, char *args[]) +{ + + +// printMemUse(); + printFreeList(); + + + return 0; +} + + +/*------------------------------------------------------------------------ + * printFreeList - Walk the list of free memory blocks and print the + * location and size of each + *------------------------------------------------------------------------ + */ +static void printFreeList(void) +{ +// char t[80]; + struct memblk *block; + + /* Output a heading for the free list */ + +// printf("Free:\n"); + printf("FreeMEM: addr len\n"); + + // avr_printf(m11); + for (block = memlist.mnext; block != NULL; block = block->mnext) { + printf("0x%08x %d\n", block, + (uint32) block->mlength); + } + long i; + int j=0; + char * c = 0; + for (i=0; i<0x5bd ; i++) { + c = (char *)i; + if (j==0) { + serial_put_char('\n'); + serial_put_char('\r'); + printf ("0x%08x ", c); + } + j++; + if (j==16) j=0; + if (*c < 33) + serial_put_char('-'); + else + serial_put_char(*c); + } +} + +extern void start(void); +extern void *_end; + +/*------------------------------------------------------------------------ + * printMemUse - Print statistics about memory use + *------------------------------------------------------------------------ + */ +static void printMemUse(void) +{ + int i; /* Index into process table */ + uint32 code = 0; /* Total Xinu code memory */ + uint32 stack = 0; /* Total used stack memory */ + uint32 kheap = 0; /* Free kernel heap memory */ + uint32 kfree = 0; /* Total free memory */ + struct memblk *block; /* Ptr to memory block */ + + /* Calculate amount of text memory */ + +// code = (uint32)&etext - (uint32)&text; + + /* Calculate amount of allocated stack memory */ + /* Skip the NULL process since it has a private stack */ + + for (i = 0; i < NPROC; i++) { + if (proctab[i].prstate != PR_FREE) { + stack += (uint32)proctab[i].prstklen; + } + } + + /* Calculate the amount of memory on the free list */ + + for (block = memlist.mnext; block != NULL; block = block->mnext) { + kfree += block->mlength; + } + + /* Calculate the amount of free kernel heap memory */ + + kheap = kfree - stack; + + /* Output statistics on current memory use */ + +// printf("code: %10d\n", (uint32) code); +// printf("stack:%10d bytes\n", (uint32) stack); +// printf("kernel stk:%10d bytes\n", (uint32) mspstack); +// printf("heap:%10d bytes\n\n", (uint32) kheap); +} diff --git a/shell/README b/shell/README new file mode 100644 index 0000000..fc9b5b4 --- /dev/null +++ b/shell/README @@ -0,0 +1,6 @@ + +This app needs the below modificationes into conf/Configuration file: + +#define NPROC 3 /* number of user processes */ +#define NSEM 2 /* number of semaphores */ + diff --git a/shell/backup/addargs.c b/shell/backup/addargs.c new file mode 100644 index 0000000..48580f6 --- /dev/null +++ b/shell/backup/addargs.c @@ -0,0 +1,119 @@ +/* addargs.c - addargs */ + +#include +#include "shprototypes.h" + +/*------------------------------------------------------------------------ + * addargs - Add local copy of argv-style arguments to the stack of + * a command process that has been created by the shell + *------------------------------------------------------------------------ + */ +status addargs( + pid32 pid, /* ID of process to use */ + int32 ntok, /* Count of arguments */ + int32 tok[], /* Index of tokens in tokbuf */ + int32 tlen, /* Length of data in tokbuf */ + char *tokbuf, /* Array of null-term. tokens */ + void *dummy /* Dummy argument that was */ + /* used at creation and must */ + /* be replaced by a pointer */ + /* to an argument vector */ + ) +{ + intmask mask; /* Saved interrupt mask */ + struct procent *prptr; /* Ptr to process' table entry */ + uint32 aloc; /* Argument location in process */ + /* stack as an integer */ + uint32 *argloc; /* Location in process's stack */ + /* to place args vector */ + char *argstr; /* Location in process's stack */ + /* to place arg strings */ + uint32 *search; /* pointer that searches for */ + /* dummy argument on stack */ + uint32 *aptr; /* Walks through args array */ + int32 i; /* Index into tok array */ + + mask = disable(); + + /* Check argument count and data length */ + + if ( (ntok <= 0) || (tlen < 0) ) { + // serial_put_char('M'); + restore(mask); + return SYSERR; + } + + prptr = &proctab[pid]; + + /* Compute lowest location in the process stack where the */ + /* args array will be stored followed by the argument */ + /* strings */ + +// aloc = (uint32) (prptr->prstkbase +// - prptr->prstklen + sizeof(uint32)); +// argloc = (uint32*) ((aloc + 3) & ~0x3); /* round multiple of 4 */ + + /* Compute the first location beyond args array for the strings */ +// +// argstr = (char *) (argloc + (ntok+1)); /* +1 for a null ptr */ + + /* Set each location in the args vector to be the address of */ + /* string area plus the offset of this argument */ + +// for (aptr=argloc, i=0; i < ntok; i++) { +// *aptr++ = (uint32) (argstr + tok[i]); +// } + + /* Add a null pointer to the args array */ + +// *aptr++ = (uint32)NULL; + + /* Copy the argument strings from tokbuf into process's stack */ + /* just beyond the args vector */ + +// memcpy(aptr, tokbuf, tlen); + + /* Find the second argument in process's stack */ + +// for (search = (uint32 *)prptr->prstkptr; +// search < (uint32 *)prptr->prstkbase; search++) { + + /* If found, replace with the address of the args vector*/ + +// if (*search == (uint32)dummy) { +// *search = (uint32)argloc; +// restore(mask); +// return OK; +// } +// } + + /* Argument value not found on the stack - report an error */ + + // serial_put_char('\n'); + +// for (fromarg=Shl.shtok ; nargs > 0 ; nargs--) { + for (i=0 ; i < ntok; i++) { + // prptr->parg[i+prptr->pargs] = (int)tok[i]; /******** change int parg[] TO void *parg[] in proc.h ******/ + // prptr->parg[i+prptr->pargs] = (void *)tok[i]; /******** change int parg[] TO void *parg[] in proc.h ******/ +// serial_put_char(48+i); +// serial_put_char(' '); +// serial_put_char(tokbuf[tok[i]]); +// serial_put_char(' '); + prptr->parg[i] = &tokbuf[tok[i]]; + + } +// *toarg = 0; + prptr->pargs = ntok; + prptr->parg[ntok] = 0; + +// RAFA prptr->pargs += ntok; +// RAFA prptr->parg[prptr->pargs] = 0; + /* machine/compiler dependent pass arguments to created process */ + prptr->pregs[24] = lobyte((unsigned)prptr->pargs); /*r24*/ + prptr->pregs[25] = hibyte((unsigned)prptr->pargs); + + + restore(mask); + return OK; +// return SYSERR; +} diff --git a/shell/backup/lexan.c b/shell/backup/lexan.c new file mode 100644 index 0000000..4e0cb8b --- /dev/null +++ b/shell/backup/lexan.c @@ -0,0 +1,148 @@ +/* lexan.c - lexan */ + +#include + +/*------------------------------------------------------------------------ + * lexan - Ad hoc lexical analyzer to divide command line into tokens + *------------------------------------------------------------------------ + */ + +int32 lexan ( + char *line, /* Input line terminated with */ + /* NEWLINE or NULLCH */ + int32 len, /* Length of the input line, */ + /* including NEWLINE */ + char *tokbuf, /* Buffer into which tokens are */ + /* stored with a null */ + /* following each token */ + int32 *tlen, /* Place to store number of */ + /* chars in tokbuf */ + int32 tok[], /* Array of pointers to the */ + /* start of each token */ + int32 toktyp[] /* Array that gives the type */ + /* of each token */ + ) +{ + char quote; /* Character for quoted string */ + uint32 ntok; /* Number of tokens found */ + char *p; /* Pointer that walks along the */ + /* input line */ + int32 tbindex; /* Index into tokbuf */ + char ch; /* Next char from input line */ + + /* Start at the beginning of the line with no tokens */ + + ntok = 0; + p = line; + tbindex = 0; + + /* While not yet at end of line, get next token */ + + while ( (*p != NULLCH) && (*p != SH_NEWLINE) ) { + + /* If too many tokens, return error */ + + if (ntok >= SHELL_MAXTOK) { + return SYSERR; + } + + /* Skip whitespace before token */ + + while ( (*p == SH_BLANK) || (*p == SH_TAB) ) { + p++; + } + + /* Stop parsing at end of line (or end of string) */ + + ch = *p; + if ( (ch==SH_NEWLINE) || (ch==NULLCH) ) { + *tlen = tbindex; + return ntok; + } + + /* Set next entry in tok array to be an index to the */ + /* current location in the token buffer */ + + tok[ntok] = tbindex; /* the start of the token */ + + /* Set the token type */ + + switch (ch) { + + case SH_AMPER: toktyp[ntok] = SH_TOK_AMPER; + tokbuf[tbindex++] = ch; + tokbuf[tbindex++] = NULLCH; + ntok++; + p++; + continue; + + case SH_LESS: toktyp[ntok] = SH_TOK_LESS; + tokbuf[tbindex++] = ch; + tokbuf[tbindex++] = NULLCH; + ntok++; + p++; + continue; + + case SH_GREATER: toktyp[ntok] = SH_TOK_GREATER; + tokbuf[tbindex++] = ch; + tokbuf[tbindex++] = NULLCH; + ntok++; + p++; + continue; + + default: toktyp[ntok] = SH_TOK_OTHER; + }; + + /* Handle quoted string (single or double quote) */ + + if ( (ch==SH_SQUOTE) || (ch==SH_DQUOTE) ) { + quote = ch; /* remember opening quote */ + + /* Copy quoted string to arg area */ + + p++; /* Move past starting quote */ + + while ( ((ch=*p++) != quote) && (ch != SH_NEWLINE) + && (ch != NULLCH) ) { + tokbuf[tbindex++] = ch; + } + if (ch != quote) { /* string missing end quote */ + return SYSERR; + } + + /* Finished string - count token and go on */ + + tokbuf[tbindex++] = NULLCH; /* terminate token */ + ntok++; /* count string as one token */ + continue; /* go to next token */ + } + + /* Handle a token other than a quoted string */ + + tokbuf[tbindex++] = ch; /* put first character in buffer*/ + p++; + + while ( ((ch = *p) != SH_NEWLINE) && (ch != NULLCH) + && (ch != SH_LESS) && (ch != SH_GREATER) + && (ch != SH_BLANK) && (ch != SH_TAB) + && (ch != SH_AMPER) && (ch != SH_SQUOTE) + && (ch != SH_DQUOTE) ) { + tokbuf[tbindex++] = ch; + p++; + } + + /* Report error if other token is appended */ + + if ( (ch == SH_SQUOTE) || (ch == SH_DQUOTE) + || (ch == SH_LESS) || (ch == SH_GREATER) ) { + return SYSERR; + } + + tokbuf[tbindex++] = NULLCH; /* terminate the token */ + + ntok++; /* count valid token */ + + } + *tlen = tbindex; + return ntok; +} diff --git a/shell/shell.c b/shell/backup/shell.c similarity index 98% rename from shell/shell.c rename to shell/backup/shell.c index 5ee23aa..1ff6080 100644 --- a/shell/shell.c +++ b/shell/backup/shell.c @@ -8,9 +8,8 @@ /* Table of Xinu shell commands and the function associated with each */ /************************************************************************/ const struct cmdent cmdtab[] = { - {"memstat", FALSE, xsh_memstat}, /* Make built-in */ + {"memstat", TRUE, xsh_memstat}, /* Make built-in */ {"editor", FALSE, xsh_editor}, /* Make built-in */ - {"basic", FALSE, xsh_basic}, /* Make built-in */ {"echo", FALSE, xsh_echo} // {"argecho", TRUE, xsh_argecho}, // {"cat", FALSE, xsh_cat}, @@ -287,7 +286,7 @@ process shell ( // RAFA cmdtab[j].cname, 2, ntok, &tmparg); /* 160 bytes de stack perfecto */ child = create(cmdtab[j].cfunc, - 460, SHELL_CMDPRIO, + 160, SHELL_CMDPRIO, cmdtab[j].cname, 2, ntok, &tmparg); /* If creation or argument copy fails, report error */ diff --git a/shell/test.c b/shell/backup/test.c similarity index 93% rename from shell/test.c rename to shell/backup/test.c index 1947ebe..4686966 100644 --- a/shell/test.c +++ b/shell/backup/test.c @@ -40,6 +40,7 @@ process test(int nargs, char *args[]) { // int32 a = roundmb(81); +/* EEPROM TEST char buf[6]; char buf2[6]; memset(buf, 0, 6); @@ -59,7 +60,8 @@ process test(int nargs, char *args[]) blink_avr(); blink_avr(); blink_avr(); -/* + EN EEPROM TEST */ + sid32 produced, consumed; consumed = semcreate(0); produced = semcreate(1); @@ -67,9 +69,8 @@ process test(int nargs, char *args[]) printf ("consu=%d \n", consumed); blink_avr(); blink_avr(); - resume(create(cons2, 256, 20, "cons", 3, consumed, produced, 4)); - resume(create(prod2, 256, 20, "prod", 3, consumed, produced, 4)); -*/ + resume(create(cons2, 200, 20, "cons", 3, consumed, produced, 4)); + resume(create(prod2, 200, 20, "prod", 3, consumed, produced, 4)); return 0; } diff --git a/shell/backup/xsh_echo.c b/shell/backup/xsh_echo.c new file mode 100644 index 0000000..393c81a --- /dev/null +++ b/shell/backup/xsh_echo.c @@ -0,0 +1,24 @@ +/* xsh_echo.c - xsh_echo */ + +#include +#include + +/*------------------------------------------------------------------------ + * xhs_echo - write argument strings to stdout + *------------------------------------------------------------------------ + */ +shellcmd xsh_echo(int nargs, char *args[]) +{ + int32 i; /* walks through args array */ + + if (nargs > 1) { + printf("%s", args[1]); + + for (i = 2; i < nargs; i++) { + printf(" %s", args[i]); + } + } + printf("\n"); + + return 0; +} diff --git a/shell/backup/xsh_editor.c b/shell/backup/xsh_editor.c new file mode 100644 index 0000000..616b855 --- /dev/null +++ b/shell/backup/xsh_editor.c @@ -0,0 +1,94 @@ +/* xsh_editor.c - xsh_editor */ + +#include +#include + +#define NLINES 10 +#define LINE_LEN 24 +/*------------------------------------------------------------------------ + * xhs_editor - text editor + *------------------------------------------------------------------------ + */ +shellcmd xsh_editor(int nargs, char *args[]) +{ + +/* + int32 i; + + if (nargs > 1) { + printf("%s", args[1]); + + for (i = 2; i < nargs; i++) { + printf(" %s", args[i]); + } + } + printf("\n"); +*/ + char buffer[NLINES][LINE_LEN+1]; + int page = 0; + int i = 0; + int dev = 0; + int c; + int cursor = 0; + int line = 0; + + fprintf(dev, "\033[2J"); + fprintf(dev, "\033[H"); + fprintf(dev, "Text editor. page: %i\n", page); + + memset(buffer, NLINES*(LINE_LEN+1), 0); + for (i=0; i LINE_LEN) { + cursor = 0; + line++; + printf("\n\r"); + } + break; + default: + break; + } + } + continue; + } + + printf("%c", c); + buffer[line][cursor] = c; + cursor++; + if (cursor > LINE_LEN) { + cursor = 0; + line++; + printf("\n\r"); + if (line > NLINES) { + // pasar_pagina(); + } + } + + } + + + // RAFA + return 0; +} diff --git a/shell/backup/xsh_memstat.c b/shell/backup/xsh_memstat.c new file mode 100644 index 0000000..15fe97d --- /dev/null +++ b/shell/backup/xsh_memstat.c @@ -0,0 +1,116 @@ +/* xsh_memstat.c - xsh_memstat */ + +#include +#include +#include + +static void printMemUse(void); +static void printFreeList(void); + +/*------------------------------------------------------------------------ + * xsh_memstat - Print statistics about memory use and dump the free list + *------------------------------------------------------------------------ + */ +shellcmd xsh_memstat(int nargs, char *args[]) +{ + + /* For argument '--help', emit help about the 'memstat' command */ + +/* + if (nargs == 2 && strncmp(args[1], "--help", 7) == 0) { + printf("use: %s \n\n", args[0]); + printf("Description:\n"); + printf("\tDisplays the current memory use and prints the\n"); + printf("\tfree list.\n"); + printf("Options:\n"); + printf("\t--help\t\tdisplay this help and exit\n"); + return 0; + } +*/ + + /* Check for valid number of arguments */ + +/* + if (nargs > 1) { + fprintf(stderr, "%s: too many arguments\n", args[0]); + fprintf(stderr, "Try '%s --help' for more information\n", + args[0]); + return 1; + } +*/ + + printMemUse(); + printFreeList(); + + return 0; +} + + +/*------------------------------------------------------------------------ + * printFreeList - Walk the list of free memory blocks and print the + * location and size of each + *------------------------------------------------------------------------ + */ +static void printFreeList(void) +{ + char t[80]; + struct memblk *block; + + /* Output a heading for the free list */ + +// printf("Free:\n"); + printf("FreeMEM: addr len\n"); + + // avr_printf(m11); + for (block = memlist.mnext; block != NULL; block = block->mnext) { + printf("0x%08x %d\n", block, + (uint32) block->mlength); + } +} + +extern void start(void); +extern void *_end; + +/*------------------------------------------------------------------------ + * printMemUse - Print statistics about memory use + *------------------------------------------------------------------------ + */ +static void printMemUse(void) +{ + int i; /* Index into process table */ + uint32 code = 0; /* Total Xinu code memory */ + uint32 stack = 0; /* Total used stack memory */ + uint32 kheap = 0; /* Free kernel heap memory */ + uint32 kfree = 0; /* Total free memory */ + struct memblk *block; /* Ptr to memory block */ + + /* Calculate amount of text memory */ + +// code = (uint32)&etext - (uint32)&text; + + /* Calculate amount of allocated stack memory */ + /* Skip the NULL process since it has a private stack */ + + for (i = 0; i < NPROC; i++) { + if (proctab[i].prstate != PR_FREE) { + stack += (uint32)proctab[i].prstklen; + } + } + + /* Calculate the amount of memory on the free list */ + + for (block = memlist.mnext; block != NULL; block = block->mnext) { + kfree += block->mlength; + } + + /* Calculate the amount of free kernel heap memory */ + + kheap = kfree - stack; + + /* Output statistics on current memory use */ + +// printf("code: %10d\n", (uint32) code); +// printf("stack:%10d bytes\n", (uint32) stack); +// printf("kernel stk:%10d bytes\n", (uint32) mspstack); +// printf("heap:%10d bytes\n\n", (uint32) kheap); +} diff --git a/shell/main.c b/shell/main.c new file mode 100644 index 0000000..7ea271b --- /dev/null +++ b/shell/main.c @@ -0,0 +1,343 @@ +/* main.c - main */ + +/* shell.c - shell */ + + +#include +//#include +#include "shprototypes.h" + +void xsh_help(void) +{ + int i; + + printf("\n\rCommands:\n\n\r"); + for (i=0; i output_file */ +/* */ +/************************************************************************/ + +process main(void) +{ + char buf[SHELL_BUFLEN]; /* Input line (large enough for */ + int32 len; /* Length of line read */ + char tokbuf[SHELL_BUFLEN + /* Buffer to hold a set of */ + SHELL_MAXTOK]; /* Contiguous null-terminated */ + int32 tlen; /* Current length of all data */ + /* in array tokbuf */ + int32 tok[SHELL_MAXTOK]; /* Index of each token in */ + int32 toktyp[SHELL_MAXTOK]; /* Type of each token in tokbuf */ + int32 ntok; /* Number of tokens on line */ + pid32 child; /* Process ID of spawned child */ + bool8 backgnd; /* Run command in background? */ + char *outname, *inname; /* Pointers to strings for file */ + /* names that follow > and < */ + did32 stdinput, stdoutput; /* Descriptors for redirected */ + /* input and output */ + int32 i; /* Index into array of tokens */ + int32 j; /* Index into array of commands */ + int32 msg; /* Message from receive() for */ + /* child termination */ + int32 tmparg; /* Address of this var is used */ + /* when first creating child */ + /* process, but is replaced */ + char *src, *cmp; /* Pointers used during name */ + /* comparison */ + bool8 diff; /* Was difference found during */ + char *args[SHELL_MAXTOK]; /* Argument vector passed to */ + /* builtin commands */ + did32 dev = 0; /* ID of tty device from which */ + + /* Print shell banner and startup message */ + +/* + fprintf(dev, "\n\n%s%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", + SHELL_BAN0,SHELL_BAN1,SHELL_BAN2,SHELL_BAN3,SHELL_BAN4, + SHELL_BAN5,SHELL_BAN6,SHELL_BAN7,SHELL_BAN8,SHELL_BAN9,SHELL_BAN10); + + fprintf(dev, "%s\n\n", SHELL_STRTMSG); +*/ + + /* Continually prompt the user, read input, and execute command */ + + + while (TRUE) { + + // RAFA + // fprintf(dev, "\033[2J"); + // fprintf(dev, "\033[H"); + + /* Display prompt */ + fprintf(dev, SHELL_PROMPT); + + + len = read(dev, buf, sizeof(buf)); + + /* Exit gracefully on end-of-file */ + + if (len == EOF) { + break; + } + + /* If line contains only NEWLINE, go to next line */ + + if (len <= 1) { + continue; + } + + buf[len] = SH_NEWLINE; /* terminate line */ + + /* Parse input line and divide into tokens */ + + ntok = lexan(buf, len, tokbuf, &tlen, tok, toktyp); + + /* Handle parsing error */ + + if (ntok == SYSERR) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + + /* If line is empty, go to next input line */ + + if (ntok == 0) { + // fprintf(dev, "\n"); + continue; + } + + /* If last token is '&', set background */ + + if (toktyp[ntok-1] == SH_TOK_AMPER) { + ntok-- ; + tlen-= 2; + backgnd = TRUE; + } else { + backgnd = FALSE; + } + + + /* Check for input/output redirection (default is none) */ + + outname = inname = NULL; + if ( (ntok >=3) && ( (toktyp[ntok-2] == SH_TOK_LESS) + ||(toktyp[ntok-2] == SH_TOK_GREATER))){ + if (toktyp[ntok-1] != SH_TOK_OTHER) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + if (toktyp[ntok-2] == SH_TOK_LESS) { + inname = &tokbuf[tok[ntok-1]]; + } else { + outname = &tokbuf[tok[ntok-1]]; + } + ntok -= 2; + tlen = tok[ntok]; + } + + + if ( (ntok >=3) && ( (toktyp[ntok-2] == SH_TOK_LESS) + ||(toktyp[ntok-2] == SH_TOK_GREATER))){ + if (toktyp[ntok-1] != SH_TOK_OTHER) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + if (toktyp[ntok-2] == SH_TOK_LESS) { + if (inname != NULL) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + inname = &tokbuf[tok[ntok-1]]; + } else { + if (outname != NULL) { + // fprintf(dev,"%s\n", SHELL_SYNERRMSG); + continue; + } + outname = &tokbuf[tok[ntok-1]]; + } + ntok -= 2; + tlen = tok[ntok]; + } + + /* Verify remaining tokens are type "other" */ + + for (i=0; i= ncmd) { + // fprintf(dev, "command %s not found\n", tokbuf); + continue; + } + + /* Handle built-in command */ + + if (cmdtab[j].cbuiltin) { /* No background or redirect. */ + if (inname != NULL || outname != NULL || backgnd){ + // fprintf(dev, SHELL_BGERRMSG); + continue; + } else { + /* Set up arg vector for call */ + + for (i=0; i