Просмотр исходного кода

BRFS now does not keep track of directory anymore. Added path traversal and more.

bart 8 месяцев назад
Родитель
Сommit
3a5ff93ec6
2 измененных файлов с 350 добавлено и 184 удалено
  1. 305 182
      BCC/userBDOS/BRFS.C
  2. 45 2
      BCC/userBDOS/LIB/STDLIB.C

+ 305 - 182
BCC/userBDOS/BRFS.C

@@ -39,20 +39,28 @@ Implementation Details:
   - (1) file size [in words, not bytes]
 */
 
+/*
+Implementation Notes:
+- Current directory is managed by the application/OS, not the FS. Directory (or file) can be checked to exist using stat()
+- Updating a file: might be better to delete and create a new one, but this is better be done by the application instead of the FS
+- Write should start writing at the cursor and jump to the next block (also create in FAT) if the end is reached
+- No delete/backspace, only delete entire file or overwrite data
+*/
+
 /*
 Required operations:
-- Format
-- Create directory
-- Create file
-- Open file (allow multiple files open at once)
-- Close file (update dir entry and check/update all FAT entries)
-- Set cursor
-- Get cursor
-- Read file
-- Write file
-- Delete entire file (deleting part of file is not a thing)
-- Change directory
-- List directory
+- [x] Format
+- [x] Create directory
+- [x] Create file
+- [] Open file (not a dir!) (allow multiple files open at once)
+- [] Close file (update dir entry and check/update all FAT entries)
+- [] Stat (returns dir entry)
+- [] Set cursor
+- [] Get cursor
+- [] Read file
+- [] Write file
+- [] Delete entire file (deleting part of file is not a thing)
+- [x] List directory
 */
 
 #define word char
@@ -63,12 +71,14 @@ Required operations:
 
 #define BRFS_RAM_STORAGE_ADDR 0x600000
 
+#define MAX_PATH_LENGTH 127
+
+// Length of structs, should not be changed
 #define SUPERBLOCK_SIZE 16
+#define DIR_ENTRY_SIZE 8
 
 word *brfs_ram_storage = (word*) BRFS_RAM_STORAGE_ADDR; // RAM storage of file system
 
-word brfs_current_dir = 0; // Current directory index, points to block in data section
-
 // 16 words long
 struct brfs_superblock
 {
@@ -89,6 +99,144 @@ struct brfs_dir_entry
   word filesize;          // file size in words, not bytes
 };
 
+/**
+ * Create a hexdump like dump of a section of memory
+ * addr: address of the section
+ * len: length of the section in words
+ * linesize: number of words per line to print
+*/
+void brfs_dump_section(word* addr, word len, word linesize)
+{
+  char buf[16];
+  word i;
+  for (i = 0; i < len; i++)
+  {
+    itoah(addr[i], buf);
+    if (strlen(buf+2) == 1)
+      uprintc('0');
+    uprint(buf+2);
+
+    uprintc(' ');
+
+    // newline every linesize words
+    // also print last linesize words as chars if alphanum
+    if (i != 0 && MATH_modU(i+1, linesize) == 0)
+    {
+      uprint("  ");
+      word j;
+      for (j = i - (linesize-1); j < i+1; j++)
+      {
+        if (isalnum(addr[j]) || addr[j] == ' ')
+          uprintc(addr[j]);
+        else
+          uprintc('.');
+      }
+      uprintc('\n');
+    }
+  }
+}
+
+
+/**
+ * Create a raw filesystem dump over UART
+ * fatsize: size of the FAT table in words
+ * datasize: size of the data section in words
+*/
+void brfs_dump(word fatsize, word datasize)
+{
+  // Superblock dump
+  uprintln("Superblock:");
+  brfs_dump_section(brfs_ram_storage, SUPERBLOCK_SIZE, 16);
+
+  // FAT dump
+  uprintln("\nFAT:");
+  brfs_dump_section(brfs_ram_storage+SUPERBLOCK_SIZE, fatsize, 8);
+
+  // Datablock dump
+  uprintln("\nData:");
+  brfs_dump_section(brfs_ram_storage+SUPERBLOCK_SIZE+fatsize, datasize, 32);
+
+  uprintc('\n');
+}
+
+
+/**
+ * Return the FAT index of a directory, or -1 if not found
+ * dir_path: full path of the directory
+*/
+word brfs_get_fat_idx_of_dir(char* dir_path)
+{
+  // Check length of path
+  if (strlen(dir_path) > MAX_PATH_LENGTH)
+  {
+    uprintln("Path too long!");
+    return -1;
+  }
+
+  // Start with root directory
+  word current_dir_fat_idx = 0;
+
+  // Check if root directory is requested
+  if (strcmp(dir_path, "/") == 1)
+  {
+    return current_dir_fat_idx;
+  }
+
+  // Copy dir_path, size + 1 for null terminator
+  // Since strtok modifies the string
+  char dir_path_copy[MAX_PATH_LENGTH+1];
+  strcpy(dir_path_copy, dir_path);
+
+  struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
+  word* brfs_data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
+  word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
+
+  // Split path by '/' and traverse directories
+  char* token = strtok(dir_path_copy, "/");
+  while (token != (word*)-1)
+  {
+    // Find token in current directory
+    word* dir_addr = brfs_data_block_addr + (current_dir_fat_idx * superblock->bytes_per_block);
+    word found_dir = 0; // Keep track if token is found in current directory
+    word i;
+    for (i = 0; i < dir_entries_max; i++)
+    {
+      struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
+      if (dir_entry->filename[0] != 0)
+      {
+        char decompressed_filename[16];
+        strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
+        if (strcmp(decompressed_filename, token) == 1)
+        {
+          // Found token in current directory
+          // Set current directory to token's FAT index
+          current_dir_fat_idx = dir_entry->fat_idx;
+          found_dir = 1;
+          break;
+        }
+      }
+    }
+
+    // If token not found in current directory, return -1
+    if (!found_dir)
+    {
+      uprint("Directory ");
+      uprint(dir_path);
+      uprintln(" not found!");
+      return -1;
+    }
+
+    token = strtok((word*)-1, "/");
+  }
+  return current_dir_fat_idx;
+}
+
+/**
+ * Given the address of the FAT table and the number of blocks, find the next free block
+ * Returns -1 if no free block is found
+ * fat_addr: address of the FAT table
+ * blocks: number of blocks in the FAT table
+*/
 word brfs_find_next_free_block(word* fat_addr, word blocks)
 {
   word i = 0;
@@ -108,6 +256,12 @@ word brfs_find_next_free_block(word* fat_addr, word blocks)
   return -1;
 }
 
+/**
+ * Given the address of a directory data block and the maximum number of entries, find the next free directory entry
+ * Returns -1 if no free entry is found
+ * dir_addr: address of the directory data block (not the FAT idx)
+ * dir_entries_max: maximum number of entries in the directory
+*/
 word brfs_find_next_free_dir_entry(word* dir_addr, word dir_entries_max)
 {
   word i = 0;
@@ -127,15 +281,23 @@ word brfs_find_next_free_dir_entry(word* dir_addr, word dir_entries_max)
   return -1;
 }
 
+/**
+ * Create a single directory entry
+ * dir_entry: pointer to the directory entry to be created
+ * filename: name of the file, max 16 chars and uncompressed
+ * fat_idx: index of the first FAT block of the file/directory
+ * filesize: size of the file in words
+ * flags: flags of the file/directory
+*/
 void brfs_create_single_dir_entry(struct brfs_dir_entry* dir_entry, char* filename, word fat_idx, word filesize, word flags)
 {
   // Initialize to 0
-  memset(dir_entry, 0, sizeof(*dir_entry));
+  memset((char*)dir_entry, 0, sizeof(*dir_entry));
 
   // Set filename
   char compressed_filename[4] = {0,0,0,0};
   strcompress(compressed_filename, filename);
-  memcpy(&(dir_entry->filename), compressed_filename, sizeof(compressed_filename));
+  memcpy((char*)&(dir_entry->filename), compressed_filename, sizeof(compressed_filename));
 
   // Set other fields
   dir_entry->fat_idx = fat_idx;
@@ -143,178 +305,101 @@ void brfs_create_single_dir_entry(struct brfs_dir_entry* dir_entry, char* filena
   dir_entry->filesize = filesize;
 }
 
+/**
+ * Initialize a directory with . and .. entries
+ * dir_addr: address of the directory data block
+ * dir_entries_max: maximum number of entries in the directory
+ * dir_fat_idx: index of the FAT block of the directory
+ * parent_fat_idx: index of the FAT block of the parent directory
+*/
 void brfs_init_directory(word* dir_addr, word dir_entries_max, word dir_fat_idx, word parent_fat_idx)
 {
   // Create . entry
   struct brfs_dir_entry dir_entry;
   brfs_create_single_dir_entry(&dir_entry, ".", dir_fat_idx, dir_entries_max*sizeof(struct brfs_dir_entry), 1);
   // Copy to first data entry
-  memcpy(dir_addr, &dir_entry, sizeof(dir_entry));
+  memcpy(dir_addr, (char*)&dir_entry, sizeof(dir_entry));
 
   // Create .. entry
   brfs_create_single_dir_entry(&dir_entry, "..", parent_fat_idx, dir_entries_max*sizeof(struct brfs_dir_entry), 1);
   // Copy to second data entry
-  memcpy(dir_addr+sizeof(dir_entry), &dir_entry, sizeof(dir_entry));
+  memcpy(dir_addr+sizeof(dir_entry), (char*)&dir_entry, sizeof(dir_entry));
 
   // Set FAT table
   brfs_ram_storage[SUPERBLOCK_SIZE + dir_fat_idx] = -1;
 }
 
-// Creates hexdump like dump
-void brfs_dump_section(word* addr, word len, word linesize)
-{
-  char buf[16];
-  word i;
-  for (i = 0; i < len; i++)
-  {
-    itoah(addr[i], buf);
-    if (strlen(buf+2) == 1)
-      uprintc('0');
-    uprint(buf+2);
-
-    uprintc(' ');
-
-    // newline every linesize words
-    // also print last linesize words as chars if alphanum
-    if (i != 0 && MATH_modU(i+1, linesize) == 0)
-    {
-      uprint("  ");
-      word j;
-      for (j = i - (linesize-1); j < i+1; j++)
-      {
-        if (isalnum(addr[j]) || addr[j] == ' ')
-          uprintc(addr[j]);
-        else
-          uprintc('.');
-      }
-      uprintc('\n');
-    }
-  }
-}
-
-void brfs_dump(word* ram_addr, word fatsize, word datasize)
-{
-  // Superblock dump
-  uprintln("Superblock:");
-  brfs_dump_section(ram_addr, SUPERBLOCK_SIZE, 16);
-
-  // FAT dump
-  uprintln("\nFAT:");
-  brfs_dump_section(ram_addr+SUPERBLOCK_SIZE, fatsize, 8);
-
-  // Datablock dump
-  uprintln("\nData:");
-  brfs_dump_section(ram_addr+SUPERBLOCK_SIZE+fatsize, datasize, 32);
-
-  uprintc('\n');
-}
-
-void brfs_list_directory(word* ram_addr)
-{
-  struct brfs_superblock* superblock = (struct brfs_superblock*) ram_addr;
-  word* dir_addr = ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block);
-  word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
-
-  uprintln("-------------------");
-
-  word i;
-  for (i = 0; i < dir_entries_max; i++)
-  {
-    struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
-    if (dir_entry->filename[0] != 0)
-    {
-      uprint("Filename: ");
-      char decompressed_filename[16];
-      strdecompress(decompressed_filename, &(dir_entry->filename));
-      uprintln(decompressed_filename);
-      uprint("FAT idx: ");
-      uprintDec((dir_entry->fat_idx));
-      uprint("Flags: ");
-      uprintDec((dir_entry->flags));
-      uprint("Filesize: ");
-      uprintDec((dir_entry->filesize));
-      uprintc('\n');
-    }
-  }
-}
-
-void brfs_change_directory(word* ram_addr, char* dirname)
-{
-  struct brfs_superblock* superblock = (struct brfs_superblock*) ram_addr;
-  word* dir_addr = ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block);
-  word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
-
-  word i;
-  for (i = 0; i < dir_entries_max; i++)
-  {
-    struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
-    if (dir_entry->filename[0] != 0)
-    {
-      char decompressed_filename[16];
-      strdecompress(decompressed_filename, &(dir_entry->filename));
-      if (strcmp(decompressed_filename, dirname) == 1)
-      {
-        brfs_current_dir = dir_entry->fat_idx;
-        return;
-      }
-    }
-  }
-
-  uprintln("Directory not found!");
-}
-
-void brfs_format(word* ram_addr, word blocks, word bytes_per_block, char* label, word full_format)
+/**
+ * Format the ram storage as a BRFS filesystem
+ * blocks: number of blocks in the filesystem
+ * bytes_per_block: number of bytes per block
+ * label: label of the filesystem
+ * full_format: if 1, initialize data section to 0
+*/
+void brfs_format(word blocks, word bytes_per_block, char* label, word full_format)
 {
   // Create a superblock
   struct brfs_superblock superblock;
 
   // Initialize to 0
-  memset(&superblock, 0, sizeof(superblock));
+  memset((char*)&superblock, 0, sizeof(superblock));
 
   // Set values of superblock
   superblock.total_blocks = blocks;
   superblock.bytes_per_block = bytes_per_block;
-  strcpy(&(superblock.label), label);
+  strcpy((char*)&superblock.label, label);
   superblock.brfs_version = 1;
 
   // Copy superblock to head of ram addr
-  memcpy(ram_addr, &superblock, sizeof(superblock));
+  memcpy(brfs_ram_storage, (char*)&superblock, sizeof(superblock));
 
 
   // Create FAT
-  memset(ram_addr + SUPERBLOCK_SIZE, 0, blocks);
+  memset(brfs_ram_storage + SUPERBLOCK_SIZE, 0, blocks);
 
   // Create Data section
   if (full_format)
   {
-    memset(ram_addr + SUPERBLOCK_SIZE + blocks, 0, blocks * bytes_per_block);
+    memset(brfs_ram_storage + SUPERBLOCK_SIZE + blocks, 0, blocks * bytes_per_block);
   }
   
   // Initialize root dir
   word dir_entries_max = bytes_per_block / sizeof(struct brfs_dir_entry);
-  brfs_init_directory(ram_addr + SUPERBLOCK_SIZE + blocks, dir_entries_max, 0, 0);
-
-  brfs_current_dir = 0;
+  brfs_init_directory(brfs_ram_storage + SUPERBLOCK_SIZE + blocks, dir_entries_max, 0, 0);
 }
 
-/*
-* Creates directory in current directory
+/**
+ * Create a new directory in the directory of parent_dir_path
+ * parent_dir_path: full path of the parent directory
+ * dirname: name of the new directory
 */
-void brfs_create_directory(word* ram_addr, char* dirname)
+void brfs_create_directory(char* parent_dir_path, char* dirname)
 {
-  struct brfs_superblock* superblock = (struct brfs_superblock*) ram_addr;
+  struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
+
+  word* brfs_data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
 
   // Find first free FAT block
-  word next_free_block = brfs_find_next_free_block(ram_addr + SUPERBLOCK_SIZE, superblock->total_blocks);
+  word next_free_block = brfs_find_next_free_block(brfs_ram_storage + SUPERBLOCK_SIZE, superblock->total_blocks);
   if (next_free_block == -1)
   {
     uprintln("No free blocks left!");
     return;
   }
 
+  // Find data block address of parent directory path
+  word parent_dir_fat_idx = brfs_get_fat_idx_of_dir(parent_dir_path);
+  if (parent_dir_fat_idx == -1)
+  {
+    uprint("Parent directory ");
+    uprint(parent_dir_path);
+    uprintln(" not found!");
+    return;
+  }
+
   // Find first free dir entry
   word next_free_dir_entry = brfs_find_next_free_dir_entry(
-    ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block), 
+    brfs_data_block_addr + (parent_dir_fat_idx * superblock->bytes_per_block), 
     superblock->bytes_per_block / sizeof(struct brfs_dir_entry)
   );
   if (next_free_dir_entry == -1)
@@ -329,39 +414,53 @@ void brfs_create_directory(word* ram_addr, char* dirname)
 
   // Copy dir entry to first free dir entry
   memcpy(
-    ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
-    &new_entry,
+    brfs_data_block_addr + (parent_dir_fat_idx * superblock->bytes_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
+    (char*)&new_entry,
     sizeof(new_entry)
   );
 
   // Initialize directory
   word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
   brfs_init_directory(
-    ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (next_free_block * superblock->bytes_per_block),
+    brfs_data_block_addr + (next_free_block * superblock->bytes_per_block),
     dir_entries_max,
     next_free_block,
-    brfs_current_dir
+    parent_dir_fat_idx
   );
 }
 
-/*
-* Creates an empty file in current directory
+/**
+ * Create a new file in the directory of parent_dir_path
+ * parent_dir_path: full path of the parent directory
+ * filename: name of the new file
 */
-void brfs_create_file(word* ram_addr, char* filename)
+void brfs_create_file(char* parent_dir_path, char* filename)
 {
-  struct brfs_superblock* superblock = (struct brfs_superblock*) ram_addr;
+  struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
+
+  word* brfs_data_block_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks;
 
   // Find first free FAT block
-  word next_free_block = brfs_find_next_free_block(ram_addr + SUPERBLOCK_SIZE, superblock->total_blocks);
+  word next_free_block = brfs_find_next_free_block(brfs_ram_storage + SUPERBLOCK_SIZE, superblock->total_blocks);
   if (next_free_block == -1)
   {
     uprintln("No free blocks left!");
     return;
   }
 
+  // Find data block address of parent directory path
+  word parent_dir_fat_idx = brfs_get_fat_idx_of_dir(parent_dir_path);
+  if (parent_dir_fat_idx == -1)
+  {
+    uprint("Parent directory ");
+    uprint(parent_dir_path);
+    uprintln(" not found!");
+    return;
+  }
+
   // Find first free dir entry
   word next_free_dir_entry = brfs_find_next_free_dir_entry(
-    ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block), 
+    brfs_data_block_addr + (parent_dir_fat_idx * superblock->bytes_per_block), 
     superblock->bytes_per_block / sizeof(struct brfs_dir_entry)
   );
   if (next_free_dir_entry == -1)
@@ -376,20 +475,66 @@ void brfs_create_file(word* ram_addr, char* filename)
 
   // Copy dir entry to first free dir entry
   memcpy(
-    ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (brfs_current_dir * superblock->bytes_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
-    &new_entry,
+    brfs_data_block_addr + (parent_dir_fat_idx * superblock->bytes_per_block) + (next_free_dir_entry * sizeof(struct brfs_dir_entry)),
+    (char*)&new_entry,
     sizeof(new_entry)
   );
 
   // Initialize file by setting data to 0
   memset(
-    ram_addr + SUPERBLOCK_SIZE + superblock->total_blocks + (next_free_block * superblock->bytes_per_block),
+    brfs_data_block_addr + (next_free_block * superblock->bytes_per_block),
     0,
     superblock->bytes_per_block
   );
 
   // Update FAT
-  ram_addr[SUPERBLOCK_SIZE + next_free_block] = -1;
+  brfs_ram_storage[SUPERBLOCK_SIZE + next_free_block] = -1;
+}
+
+/**
+ * List the contents of a directory over UART
+ * dir_path: full path of the directory
+*/
+void brfs_list_directory(char* dir_path)
+{
+  uprint("Listing directory ");
+  uprintln(dir_path);
+  uprintln("-------------------");
+
+  // Find data block address of parent directory path
+  word dir_fat_idx = brfs_get_fat_idx_of_dir(dir_path);
+  if (dir_fat_idx == -1)
+  {
+    uprint("Parent directory ");
+    uprint(dir_path);
+    uprintln(" not found!");
+    return;
+  }
+
+  struct brfs_superblock* superblock = (struct brfs_superblock*) brfs_ram_storage;
+  word* dir_addr = brfs_ram_storage + SUPERBLOCK_SIZE + superblock->total_blocks + (dir_fat_idx * superblock->bytes_per_block);
+  word dir_entries_max = superblock->bytes_per_block / sizeof(struct brfs_dir_entry);
+
+  word i;
+  for (i = 0; i < dir_entries_max; i++)
+  {
+    struct brfs_dir_entry* dir_entry = (struct brfs_dir_entry*) (dir_addr + (i * sizeof(struct brfs_dir_entry)));
+    if (dir_entry->filename[0] != 0)
+    {
+      uprint("Filename: ");
+      char decompressed_filename[16];
+      strdecompress(decompressed_filename, (char*)&(dir_entry->filename));
+      uprint(decompressed_filename);
+      uprint(" FAT idx: ");
+      uprintDec((dir_entry->fat_idx));
+      uprint(" Flags: ");
+      uprintDec((dir_entry->flags));
+      uprint(" Filesize: ");
+      uprintDec((dir_entry->filesize));
+      uprintc('\n');
+    }
+  }
+  uprintln("");
 }
 
 
@@ -408,25 +553,21 @@ int main()
   word bytes_per_block = 32;
   word full_format = 1;
 
-  brfs_format(brfs_ram_storage, blocks, bytes_per_block, "Label", full_format);
-
-  brfs_create_file(brfs_ram_storage, "file1");
-
-  brfs_create_directory(brfs_ram_storage, "dir1");
+  brfs_format(blocks, bytes_per_block, "Label", full_format);
 
-  brfs_list_directory(brfs_ram_storage);
+  brfs_dump(blocks, blocks*bytes_per_block);
 
-  brfs_change_directory(brfs_ram_storage, "dir1");
+  brfs_list_directory("/");
 
-  brfs_create_file(brfs_ram_storage, "file2");
+  brfs_create_file("/", "file1.txt");
 
-  brfs_list_directory(brfs_ram_storage);
+  brfs_list_directory(".");
 
-  brfs_change_directory(brfs_ram_storage, "..");
+  brfs_create_directory("..", "dir1");
+  brfs_create_file("dir1", "file2.txt");
 
-  brfs_list_directory(brfs_ram_storage);
-
-  brfs_dump(brfs_ram_storage, blocks, blocks*bytes_per_block);
+  brfs_list_directory(".");
+  brfs_list_directory("dir1");
 
   return 'q';
 }
@@ -441,25 +582,7 @@ void interrupt()
       timer1Value = 1; // notify ending of timer1
       break;
 
-    case INTID_TIMER2:
-      break;
-
-    case INTID_UART0:
-      break;
-
-    case INTID_GPU:
-      break;
-
-    case INTID_TIMER3:
-      break;
-
-    case INTID_PS2:
-      break;
-
-    case INTID_UART1:
-      break;
-
-    case INTID_UART2:
+    default:
       break;
   }
 }

+ 45 - 2
BCC/userBDOS/LIB/STDLIB.C

@@ -193,6 +193,51 @@ char* strchr (const char *s, char c)
   return 0;
 }
 
+char * strtok_old_str;
+/* 
+Parse str into tokens separated by characters in delim.
+If S is NULL, the last string strtok() was called with is used.
+Note that strtok() modifies the input string.
+For example:
+	char s[] = "-abc-=-def";
+	x = strtok(s, "-");		// x = "abc"
+	x = strtok(NULL, "-=");		// x = "def"
+	x = strtok(NULL, "=");		// x = NULL
+		// s = "abc\0=-def\0"
+*/
+char* strtok(char* str, const char* delim)
+{
+  if (str != (word*)-1)
+    strtok_old_str = str;
+
+  if (strtok_old_str == (word*)-1)
+    return (word*)-1;
+
+  // Return reached end of string
+  if (*strtok_old_str == 0)
+  {
+    return (word*)-1;
+  }
+  // Skip leading delimiters
+  while (strchr(delim, *strtok_old_str) != 0)
+    strtok_old_str++;
+
+  // Find end of token
+  char* start = strtok_old_str;
+  while (*strtok_old_str != 0 && strchr(delim, *strtok_old_str) == 0)
+    strtok_old_str++;
+
+  if (*strtok_old_str == 0)
+  {
+    strtok_old_str = (word*)-1;
+    return start;
+  }
+
+  *strtok_old_str = 0;
+  strtok_old_str++;
+  return start;
+}
+
 /*
 Compress a string made of one char per word, into a string made of one char per byte.
 */
@@ -486,7 +531,6 @@ void uprintDec(word i)
   char buffer[11];
   itoa(i, buffer);
   uprint(buffer);
-  uprintc('\n');
 }
 
 /*
@@ -497,7 +541,6 @@ void uprintHex(word i)
   char buffer[11];
   itoah(i, buffer);
   uprint(buffer);
-  uprintc('\n');
 }