506 lines
12 KiB
C
506 lines
12 KiB
C
/*
|
|
############################################################################
|
|
# This program is used to test the basic functions of the SD file system.
|
|
# It implements simple versions of the cat, rm, ls, echo, cd, pwd, mkdir and
|
|
# rmdir commands plus the <, > and >> file redirection operators.
|
|
# The program starts up the file driver and then prompts for a command.
|
|
#
|
|
# Written by Dave Hein
|
|
# Copyright (c) 2011 Parallax, Inc.
|
|
# MIT Licensed
|
|
############################################################################
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <cog.h>
|
|
#include <propeller.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <dirent.h>
|
|
#include "spinix.h"
|
|
|
|
extern _Driver _SimpleSerialDriver;
|
|
extern _Driver _FileDriver;
|
|
|
|
/* This is a list of all drivers we can use in the
|
|
* program. The default _InitIO function opens stdin,
|
|
* stdout, and stderr based on the first driver in
|
|
* the list (the serial driver, for us)
|
|
*/
|
|
_Driver *_driverlist[] = {
|
|
&_SimpleSerialDriver,
|
|
&_FileDriver,
|
|
NULL
|
|
};
|
|
|
|
char *FindChar(char *ptr, int val);
|
|
|
|
FILE *stdinfile;
|
|
FILE *stdoutfile;
|
|
|
|
/* Print help information */
|
|
void Help()
|
|
{
|
|
printf("Commands are help, cat, rm, ls, ll, echo, cd, pwd and exit\n");
|
|
}
|
|
|
|
void Cd(int argc, char **argv)
|
|
{
|
|
if (argc < 2) return;
|
|
|
|
if (chdir(argv[1]))
|
|
perror(argv[1]);
|
|
}
|
|
|
|
void Pwd(int argc, char **argv)
|
|
{
|
|
uint8_t buffer[64];
|
|
char *ptr = getcwd(buffer, 64);
|
|
if (!ptr)
|
|
perror(0);
|
|
else
|
|
fprintf(stdoutfile, "%s\n", ptr);
|
|
}
|
|
|
|
#if 0
|
|
void Mkdir(int argc, char **argv)
|
|
{
|
|
int i;
|
|
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
if (mkdir(argv[i], 0))
|
|
perror(argv[i]);
|
|
}
|
|
}
|
|
|
|
void Rmdir(int argc, char **argv)
|
|
{
|
|
int i;
|
|
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
if (rmdir(argv[i]))
|
|
perror(argv[i]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* This routine implements the file cat function */
|
|
void Cat(int argc, char **argv)
|
|
{
|
|
int i;
|
|
int num;
|
|
void *infile;
|
|
uint8_t buffer[40];
|
|
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
if (argc == 1 || stdinfile != stdin)
|
|
infile = stdinfile;
|
|
else
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
infile = fopen(argv[i], "r");
|
|
if (infile == 0)
|
|
{
|
|
perror(argv[i]);
|
|
continue;
|
|
}
|
|
}
|
|
if (infile == stdin)
|
|
{
|
|
while (gets(buffer))
|
|
{
|
|
if (buffer[0] == 4) break;
|
|
fprintf(stdoutfile, "%s\n", buffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while ((num = fread(buffer, 1, 40, infile)))
|
|
fwrite(buffer, 1, num, stdoutfile);
|
|
}
|
|
if (i)
|
|
fclose(infile);
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
/* This routine deletes the files specified by the command line arguments */
|
|
void Remove(int argc, char **argv)
|
|
{
|
|
int i;
|
|
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
if (remove(argv[i]))
|
|
perror(argv[i]);
|
|
}
|
|
}
|
|
|
|
/* This routine echos the command line arguments */
|
|
void Echo(int argc, char **argv)
|
|
{
|
|
int i;
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
if (i != argc - 1)
|
|
fprintf(stdoutfile, "%s ", argv[i]);
|
|
else
|
|
fprintf(stdoutfile, "%s\n", argv[i]);
|
|
}
|
|
}
|
|
|
|
/* This routine lists the root directory or any subdirectories specified
|
|
in the command line arguments. If the "-l" option is specified, it
|
|
will print the file attributes and size. Otherwise, it will just
|
|
print the file names. */
|
|
void List(int argc, char **argv)
|
|
{
|
|
int i, j;
|
|
char *ptr;
|
|
char fname[13];
|
|
int32_t count = 0;
|
|
uint32_t filesize;
|
|
uint32_t longflag = 0;
|
|
char *path;
|
|
char drwx[5];
|
|
int column;
|
|
int prevlen;
|
|
DIR *dirp;
|
|
struct dirent *entry;
|
|
|
|
// Check flags
|
|
for (j = 1; j < argc; j++)
|
|
{
|
|
if (argv[j][0] == '-')
|
|
{
|
|
if (!strcmp(argv[j], "-l"))
|
|
longflag = 1;
|
|
else
|
|
printf("Unknown option \"%s\"\n", argv[j]);
|
|
}
|
|
else
|
|
count++;
|
|
}
|
|
|
|
// List directories
|
|
for (j = 1; j < argc || count == 0; j++)
|
|
{
|
|
if (count == 0)
|
|
{
|
|
count--;
|
|
path = "./";
|
|
}
|
|
else if (argv[j][0] == '-')
|
|
continue;
|
|
else
|
|
path = argv[j];
|
|
|
|
if (count >= 2)
|
|
fprintf(stdoutfile, "\n%s:\n", path);
|
|
|
|
dirp = opendir(path);
|
|
|
|
if (!dirp)
|
|
{
|
|
perror(path);
|
|
continue;
|
|
}
|
|
|
|
column = 0;
|
|
prevlen = 14;
|
|
while (entry = readdir(dirp))
|
|
{
|
|
if (entry->name[0] == '.') continue;
|
|
ptr = fname;
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
if (entry->name[i] == ' ') break;
|
|
*ptr++ = tolower(entry->name[i]);
|
|
}
|
|
if (entry->name[8] != ' ')
|
|
{
|
|
*ptr++ = '.';
|
|
for (i = 8; i < 11; i++)
|
|
{
|
|
if (entry->name[i] == ' ') break;
|
|
*ptr++ = tolower(entry->name[i]);
|
|
}
|
|
}
|
|
*ptr = 0;
|
|
filesize = entry->filesize_3;
|
|
filesize = (filesize << 8) | entry->filesize_2;
|
|
filesize = (filesize << 8) | entry->filesize_1;
|
|
filesize = (filesize << 8) | entry->filesize_0;
|
|
strcpy(drwx, "-rw-");
|
|
if (entry->attr & ATTR_READ_ONLY)
|
|
drwx[2] = '-';
|
|
if (entry->attr & ATTR_ARCHIVE)
|
|
drwx[3] = 'x';
|
|
if (entry->attr & ATTR_DIRECTORY)
|
|
{
|
|
drwx[0] = 'd';
|
|
drwx[3] = 'x';
|
|
}
|
|
if (longflag)
|
|
fprintf(stdoutfile, "%s %8d %s\n", drwx, filesize, fname);
|
|
else if (++column == 5)
|
|
{
|
|
for (i = prevlen; i < 14; i++) fprintf(stdoutfile, " ");
|
|
fprintf(stdoutfile, "%s\n", fname);
|
|
column = 0;
|
|
prevlen = 14;
|
|
}
|
|
else
|
|
{
|
|
for (i = prevlen; i < 14; i++) fprintf(stdoutfile, " ");
|
|
prevlen = strlen(fname);
|
|
fprintf(stdoutfile, "%s", fname);
|
|
}
|
|
}
|
|
closedir(dirp);
|
|
if (!longflag && column)
|
|
fprintf(stdoutfile, "\n");
|
|
}
|
|
}
|
|
|
|
/* This routine returns a pointer to the first character that doesn't
|
|
match val. */
|
|
char *SkipChar(char *ptr, int val)
|
|
{
|
|
while (*ptr)
|
|
{
|
|
if (*ptr != val) break;
|
|
ptr++;
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
/* This routine returns a pointer to the first character that matches val. */
|
|
char *FindChar(char *ptr, int val)
|
|
{
|
|
while (*ptr)
|
|
{
|
|
if (*ptr == val) break;
|
|
ptr++;
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
/* This routine extracts tokens from a string that are separated by one or
|
|
more spaces. It returns the number of tokens found. */
|
|
int tokenize(char *ptr, char *tokens[])
|
|
{
|
|
int num = 0;
|
|
|
|
while (*ptr)
|
|
{
|
|
ptr = SkipChar(ptr, ' ');
|
|
if (*ptr == 0) break;
|
|
if (ptr[0] == '>')
|
|
{
|
|
ptr++;
|
|
if (ptr[0] == '>')
|
|
{
|
|
tokens[num++] = ">>";
|
|
ptr++;
|
|
}
|
|
else
|
|
tokens[num++] = ">";
|
|
continue;
|
|
}
|
|
if (ptr[0] == '<')
|
|
{
|
|
ptr++;
|
|
tokens[num++] = "<";
|
|
continue;
|
|
}
|
|
tokens[num++] = ptr;
|
|
ptr = FindChar(ptr, ' ');
|
|
if (*ptr) *ptr++ = 0;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
/* This routine searches the list of tokens for the redirection operators
|
|
and opens the files for input, output or append depending on the
|
|
operator. */
|
|
int CheckRedirection(char **tokens, int num)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < num-1; i++)
|
|
{
|
|
if (!strcmp(tokens[i], ">"))
|
|
{
|
|
stdoutfile = fopen(tokens[i+1], "w");
|
|
if (!stdoutfile)
|
|
{
|
|
perror(tokens[i+1]);
|
|
stdoutfile = stdout;
|
|
return 0;
|
|
}
|
|
}
|
|
else if (!strcmp(tokens[i], ">>"))
|
|
{
|
|
stdoutfile = fopen(tokens[i+1], "a");
|
|
if (!stdoutfile)
|
|
{
|
|
perror(tokens[i+1]);
|
|
stdoutfile = stdout;
|
|
return 0;
|
|
}
|
|
}
|
|
else if (!strcmp(tokens[i], "<"))
|
|
{
|
|
stdinfile = fopen(tokens[i+1], "r");
|
|
if (!stdinfile)
|
|
{
|
|
perror(tokens[i+1]);
|
|
stdinfile = stdin;
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
continue;
|
|
for (j = i + 2; j < num; j++) tokens[j-2] = tokens[j];
|
|
i--;
|
|
num -= 2;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
/* This routine closes files that were open for redirection */
|
|
void CloseRedirection()
|
|
{
|
|
if (stdinfile != stdin)
|
|
{
|
|
fclose(stdinfile);
|
|
stdinfile = stdin;
|
|
}
|
|
if (stdoutfile != stdout)
|
|
{
|
|
fclose(stdoutfile);
|
|
stdoutfile = stdout;
|
|
}
|
|
}
|
|
|
|
int getdec(char *ptr)
|
|
{
|
|
int val = 0;
|
|
while (*ptr) val = (val * 10) + *ptr++ - '0';
|
|
return val;
|
|
}
|
|
|
|
static char pins[4];
|
|
static char *CWD;
|
|
|
|
#if 0
|
|
void GetConfig(int argc, char **argv)
|
|
{
|
|
unsigned int *lptr;
|
|
char *ptr = argv[argc-1];
|
|
ptr += strlen(ptr) + 1;
|
|
ptr = (char *)(((((int)ptr) + 3) >> 2) << 2);
|
|
lptr = (unsigned int *)ptr;
|
|
//printf("%8.8x, %8.8x, %s\n", lptr[0], lptr[1], ptr + 8);
|
|
memcpy(pins, &lptr[1], 4);
|
|
CWD = ptr + 8;
|
|
}
|
|
#endif
|
|
|
|
/* The program starts the file system. It then loops reading commands
|
|
and calling the appropriate routine to process it. */
|
|
int main(int argc, char **argv)
|
|
{
|
|
int num;
|
|
char *tokens[20];
|
|
uint8_t buffer[80];
|
|
|
|
stdinfile = stdin;
|
|
stdoutfile = stdout;
|
|
|
|
spinix_enter();
|
|
|
|
printf("\n");
|
|
Help();
|
|
|
|
while (1)
|
|
{
|
|
printf("\n> ");
|
|
fflush(stdout);
|
|
gets(buffer);
|
|
num = tokenize(buffer, tokens);
|
|
num = CheckRedirection(tokens, num);
|
|
if (num == 0) continue;
|
|
if (!strcmp(tokens[0], "help"))
|
|
Help();
|
|
else if (!strcmp(tokens[0], "cat"))
|
|
Cat(num, tokens);
|
|
else if (!strcmp(tokens[0], "ls"))
|
|
List(num, tokens);
|
|
else if (!strcmp(tokens[0], "ll"))
|
|
{
|
|
tokens[num++] = "-l";
|
|
List(num, tokens);
|
|
}
|
|
else if (!strcmp(tokens[0], "rm"))
|
|
Remove(num, tokens);
|
|
else if (!strcmp(tokens[0], "echo"))
|
|
Echo(num, tokens);
|
|
else if (!strcmp(tokens[0], "cd"))
|
|
Cd(num, tokens);
|
|
else if (!strcmp(tokens[0], "pwd"))
|
|
Pwd(num, tokens);
|
|
#if 0
|
|
else if (!strcmp(tokens[0], "mkdir"))
|
|
Mkdir(num, tokens);
|
|
else if (!strcmp(tokens[0], "rmdir"))
|
|
Rmdir(num, tokens);
|
|
#endif
|
|
else if (!strcmp(tokens[0], "exit"))
|
|
spinix_exit(0);
|
|
else
|
|
{
|
|
printf("Invalid command\n");
|
|
Help();
|
|
}
|
|
CloseRedirection();
|
|
}
|
|
|
|
spinix_exit(0);
|
|
}
|
|
/*
|
|
+--------------------------------------------------------------------
|
|
| TERMS OF USE: MIT License
|
|
+--------------------------------------------------------------------
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
a copy of this software and associated documentation files
|
|
(the "Software"), to deal in the Software without restriction,
|
|
including without limitation the rights to use, copy, modify, merge,
|
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
|
and to permit persons to whom the Software is furnished to do so,
|
|
subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+------------------------------------------------------------------
|
|
*/
|
|
|