//---------------------------------------------------------------------------
// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
//
// 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 DALLAS SEMICONDUCTOR 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.
//
// Except as contained in this notice, the name of Dallas Semiconductor
// shall not be used except as stated in the Dallas Semiconductor
// Branding Policy.
//--------------------------------------------------------------------------
//
//  fish.c - Goes through the testing of the file I/O functions
//  Version 2.00
//

#include <stdio.h>
#include <ctype.h>
#include "ownet.h"
#include "owfile.h"
#include "rawmem.h"
#include "mbshaee.h"

// Defines for the menu lists
#define MAIN_MENU 0
#define VERIFY_MENU 1
#define ENTRY_MENU 2
// Defines for the switch statements for Main Menu
#define MAIN_SELECT_DEVICE 0
#define CHANGE_DIR 1
#define MAIN_LIST 2
#define MAIN_LIST_ALL 3
#define MAIN_MKDIR 4
#define MAIN_MKFILE 5
#define MAIN_WRITE_FILE 6
#define MAIN_READ_FILE 7
#define MAIN_DELETE_DIR 8
#define MAIN_DELETE_FILE 9
#define MAIN_RENAME 10
#define MAIN_WRITE_ADDFILE 11
#define MAIN_TERMINATE 12
#define MAIN_FORMAT 13
#define MAIN_QUIT 14
// Format file system on 1-Wire device.
#define VERIFY_NO 0
#define VERIFY_YES 1
// Defines for the switch statements for data entry
#define MODE_TEXT 0
#define MODE_HEX 1
// Number of devices to list
#define MAXDEVICES 10
// Max number for data entry
#define MAX_DATA 256

// External functions
extern void owClearError(void);

// Local functions
int menuSelect(int menu);
SMALLINT selectDevice(int numDevices, uchar AllDevices[][8]);
void printDeviceInfo(int portnum, uchar SNum[8]);
int getNumber(int min, int max);
int getString(char *write_buff);
void listDir(int portnum, uchar *SNum, FileEntry file, int recursive);
void file_name(DirectoryPath *, FileEntry *, int);

int main(int argc, char **argv) {
  int len, lentwo, selection;
  int done = FALSE;
  int first = TRUE;
  int portnum = 0;
  int error;
  uchar AllSN[MAXDEVICES][8];
  int NumDevices;
  int owd = 0;
  char msg[132];
  char dirname[64];
  char answer[4];
  char num[4];
  DirectoryPath dirpath;
  FileEntry file;
  int i, j, cnt, digcnt, maxwrite;
  short hnd;
  uchar data[MAX_DATA];

  // check for required port name
  if (argc != 2) {
    sprintf(msg, "1-Wire Net name required on command line!\n"
                 " (example: \"COM1\" (Win32 DS2480D),\"/dev/cua0\" "
                 "(Linux DS2480D),\"1\" (Win32 TMEX)\n");
    printf("%s\n", msg);
    return 0;
  }

  printf("\n1-Wire File Shell for the Public Domain Kit Version 0.00\n");

  if ((portnum = owAcquireEx(argv[1])) < 0) {
    OWERROR_DUMP(stdout);
    return 0;
  } else {
    // loop to do menu
    do {
      if (first) {
        selection = MAIN_SELECT_DEVICE;
        first = FALSE;
      } else
        selection = menuSelect(MAIN_MENU);

      // Main menu
      switch (selection) {

      case MAIN_SELECT_DEVICE:

        // find all parts
        // loop to find all of the devices up to MAXDEVICES
        NumDevices = 0;
        do {
          // perform the search
          if (!owNext(portnum, TRUE, FALSE))
            break;

          owSerialNum(portnum, AllSN[NumDevices], TRUE);
          NumDevices++;
        } while (NumDevices < (MAXDEVICES - 1));

        if (isJob(portnum, &AllSN[owd][0])) {
          printf("Would you like to write the programmed job "
                 "before choosing another button?(Y/N)\n");
          len = getString(&answer[0]);

          if ((answer[0] == 'Y') || (answer[0] == 'y'))
            if (!owDoProgramJob(portnum, &AllSN[owd][0]))
              OWERROR_DUMP(stderr);
        }

        // select a device
        owd = selectDevice(NumDevices, &AllSN[0]);

        // display device info
        printDeviceInfo(portnum, &AllSN[owd][0]);

        ChangeRom(portnum, &AllSN[owd][0]);

        break;

      case MAIN_FORMAT:
        if (menuSelect(VERIFY_MENU) == VERIFY_YES) {
          if (!isJob(portnum, &AllSN[owd][0]))
            owCreateProgramJob(portnum, &AllSN[owd][0]);

          owClearError();

          if (!owFormat(portnum, &AllSN[owd][0]))
            OWERROR_DUMP(stderr);
        }

        break;

      case CHANGE_DIR:
        printf("Enter the directory you want to change to from the root "
               "(/ for root): ");

        len = getString(&dirname[0]);

        cnt = 0;
        dirpath.NumEntries = 0;

        for (i = 0; i < len; i++) {
          if (dirname[i] != '/') {
            if ((cnt < 4) && (dirname[i] != '.') && isalnum(dirname[i]))
              dirpath.Entries[dirpath.NumEntries][cnt++] = dirname[i];
            else {
              if (dirname[i] == '.') {
                digcnt = 1;
                do {
                  if (isdigit(dirname[i + digcnt])) {
                    num[digcnt - 1] = dirname[i + digcnt];
                    digcnt++;
                  }
                } while (isdigit(dirname[i + digcnt]));

                file.Ext = atoi(&num[0]);
                i = i + digcnt;
              }
            }
          } else if (cnt > 0) {
            for (j = cnt; j < 4; j++)
              dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

            dirpath.NumEntries++;
            cnt = 0;
          } else if (dirname[0] == '/') {
            dirpath.NumEntries = 0;
            dirpath.Entries[0][0] = '.';
            dirpath.Entries[0][1] = ' ';
            break;
          }
        }

        if (dirname[0] == '.')
          dirpath.Ref = dirname[i];

        if (len > 1)
          dirpath.NumEntries++;

        if (!owChangeDirectory(portnum, &AllSN[owd][0], &dirpath)) {
          file_name(&dirpath, &file, FALSE);
          OWERROR_DUMP(stderr);
        }

        dirpath = owGetCurrentDir(portnum, &AllSN[owd][0]);
        printf("\nThe Current Directory Path is> ");
        if (dirpath.NumEntries == 0)
          printf(" <root> ");
        else {
          for (i = 0; i < dirpath.NumEntries; i++) {
            for (j = 0; j < 4; j++)
              printf("%c", dirpath.Entries[i][j]);
            printf("/");
          }
        }
        printf("\n");

        break;

      case MAIN_LIST:
        owClearError();
        printf("Enter the directory to list on (/ for root):  ");

        // get the directory and create a file on it
        len = getString(&dirname[0]);
        cnt = 0;
        dirpath.NumEntries = 0;
        for (i = 0; i < len; i++) {
          if (dirname[i] != '/') {
            if ((cnt < 4) && (dirname[i] != '.') && isalnum(dirname[i]))
              dirpath.Entries[dirpath.NumEntries][cnt++] = dirname[i];
            else {
              if (dirname[i] == '.') {
                digcnt = 1;
                do {
                  if (isdigit(dirname[i + digcnt])) {
                    num[digcnt - 1] = dirname[i + digcnt];
                    digcnt++;
                  }
                } while (isdigit(dirname[i + digcnt]));

                file.Ext = atoi(&num[0]);
                i = i + digcnt;
              }
            }
          } else if (cnt > 0) {
            for (j = cnt; j < 4; j++)
              dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

            dirpath.NumEntries++;
            cnt = 0;
          } else if (dirname[0] == '/') {
            dirpath.NumEntries = 0;
            dirpath.Entries[0][0] = '.';
            dirpath.Entries[0][1] = ' ';
            break;
          }
        }

        if (dirname[0] == '.')
          dirpath.Ref = dirname[i];

        if (len > 1)
          dirpath.NumEntries++;

        if (!owChangeDirectory(portnum, &AllSN[owd][0], &dirpath)) {
          file_name(&dirpath, &file, FALSE);
          OWERROR_DUMP(stderr);
        } else
          // list the files without recursion
          listDir(portnum, &AllSN[owd][0], file, FALSE);

        dirpath = owGetCurrentDir(portnum, &AllSN[owd][0]);
        printf("\nThe Current Directory Path is> ");
        if (dirpath.NumEntries == 0)
          printf(" <root> ");
        else {
          for (i = 0; i < dirpath.NumEntries; i++) {
            for (j = 0; j < 4; j++)
              printf("%c", dirpath.Entries[i][j]);
            printf("/");
          }
        }
        printf("\n");

        break;

      case MAIN_LIST_ALL:
        // list the files with recursion
        owClearError();
        dirpath.Ref = '0';
        dirpath.NumEntries = 0;
        owChangeDirectory(portnum, &AllSN[owd][0], &dirpath);

        listDir(portnum, &AllSN[owd][0], file, TRUE);

        break;

      case MAIN_MKDIR:
        printf("Enter the directory to create from <root>  ");

        len = getString(&dirname[0]);
        cnt = 0;
        dirpath.NumEntries = 0;
        for (i = 0; i < len; i++) {
          if (dirname[i] != '/') {
            if ((cnt < 4) && (dirname[i] != '.') && isalnum(dirname[i]))
              dirpath.Entries[dirpath.NumEntries][cnt++] = dirname[i];
            else {
              if (dirname[i] == '.') {
                digcnt = 1;
                do {
                  if (isdigit(dirname[i + digcnt])) {
                    num[digcnt - 1] = dirname[i + digcnt];
                    digcnt++;
                  }
                } while (isdigit(dirname[i + digcnt]));

                file.Ext = atoi(&num[0]);
                i = i + digcnt;

                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';
              } else if ((i + 1) == len) {
                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

                cnt = 0;
              }
            }
          } else if (cnt > 0) {
            for (j = cnt; j < 4; j++)
              dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

            dirpath.NumEntries++;
            cnt = 0;
          } else if (dirname[0] == '/') {
            dirpath.NumEntries = 0;
            dirpath.Entries[0][0] = '.';
            dirpath.Entries[0][1] = ' ';
            break;
          } else {
            for (j = cnt; j < 4; j++)
              dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

            cnt = 0;
          }
        }

        for (i = 0; i < 4; i++)
          file.Name[i] = dirpath.Entries[dirpath.NumEntries][i];

        if (!owChangeDirectory(portnum, &AllSN[owd][0], &dirpath)) {
          file_name(&dirpath, &file, FALSE);
          OWERROR_DUMP(stderr);
        } else {
          if (!isJob(portnum, &AllSN[owd][0]))
            owCreateProgramJob(portnum, &AllSN[owd][0]);

          owClearError();

          if (!owCreateDir(portnum, &AllSN[owd][0], &file)) {
            file_name(&dirpath, &file, TRUE);
            OWERROR_DUMP(stderr);
          }
        }

        dirpath = owGetCurrentDir(portnum, &AllSN[owd][0]);
        printf("\nThe Current Directory Path is> ");
        if (dirpath.NumEntries == 0)
          printf(" <root> ");
        else {
          for (i = 0; i < dirpath.NumEntries; i++) {
            for (j = 0; j < 4; j++)
              printf("%c", dirpath.Entries[i][j]);
            printf("/");
          }
        }
        printf("\n");

        break;

      case MAIN_MKFILE:
        printf("Enter the file name to create along with path from <root>  ");

        len = getString(&dirname[0]);
        cnt = 0;
        dirpath.NumEntries = 0;
        for (i = 0; i < len; i++) {
          if (dirname[i] != '/') {
            if ((cnt < 4) && (dirname[i] != '.') && isalnum(dirname[i]))
              dirpath.Entries[dirpath.NumEntries][cnt++] = dirname[i];
            else {
              if (dirname[i] == '.') {
                digcnt = 1;
                do {
                  if (isdigit(dirname[i + digcnt])) {
                    num[digcnt - 1] = dirname[i + digcnt];
                    digcnt++;
                  }
                } while (isdigit(dirname[i + digcnt]) && (digcnt < 5));
                num[digcnt - 1] = 0;

                file.Ext = atoi(&num[0]);

                i = i + digcnt;

                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';
              } else if ((i + 1) == len) {
                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

                cnt = 0;
              }
            }
          } else if (cnt > 0) {
            for (j = cnt; j < 4; j++)
              dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

            dirpath.NumEntries++;
            cnt = 0;
          } else if (dirname[0] == '/') {
            dirpath.NumEntries = 0;
            dirpath.Entries[0][0] = '.';
            dirpath.Entries[0][1] = ' ';
            break;
          }
        }

        for (i = 0; i < 4; i++)
          file.Name[i] = dirpath.Entries[dirpath.NumEntries][i];

        if (!owChangeDirectory(portnum, &AllSN[owd][0], &dirpath)) {
          file_name(&dirpath, &file, FALSE);
          OWERROR_DUMP(stderr);
        } else {
          if (!isJob(portnum, &AllSN[owd][0]))
            owCreateProgramJob(portnum, &AllSN[owd][0]);

          owClearError();

          if (!owCreateFile(portnum, &AllSN[owd][0], &maxwrite, &hnd, &file)) {
            file_name(&dirpath, &file, TRUE);
            OWERROR_DUMP(stderr);
          } else if (!owCloseFile(portnum, &AllSN[owd][0], hnd)) {
            OWERROR_DUMP(stderr);
          }
        }

        dirpath = owGetCurrentDir(portnum, &AllSN[owd][0]);
        printf("\nThe Current Directory Path is> ");
        if (dirpath.NumEntries == 0)
          printf(" <root> ");
        else {
          for (i = 0; i < dirpath.NumEntries; i++) {
            for (j = 0; j < 4; j++)
              printf("%c", dirpath.Entries[i][j]);
            printf("/");
          }
        }
        printf("\n");

        break;

      case MAIN_WRITE_FILE:
        printf("Enter the directory and file you would like to write to: ");

        len = getString(&dirname[0]);
        cnt = 0;
        dirpath.NumEntries = 0;

        for (i = 0; i < len; i++) {
          if (dirname[i] != '/') {
            if ((cnt < 4) && (dirname[i] != '.') && isalnum(dirname[i]))
              dirpath.Entries[dirpath.NumEntries][cnt++] = dirname[i];
            else {
              if (dirname[i] == '.') {
                digcnt = 1;
                do {
                  if (isdigit(dirname[i + digcnt])) {
                    num[digcnt - 1] = dirname[i + digcnt];
                    digcnt++;
                  }
                } while (isdigit(dirname[i + digcnt]));

                file.Ext = atoi(&num[0]);
                i = i + digcnt;

                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';
              } else if ((i + 1) == len) {
                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

                cnt = 0;
              }
            }
          } else if (cnt > 0) {
            for (j = cnt; j < 4; j++)
              dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

            dirpath.NumEntries++;
            cnt = 0;
          } else if (dirname[0] == '/') {
            dirpath.NumEntries = 0;
            dirpath.Entries[0][0] = '.';
            dirpath.Entries[0][1] = ' ';
            break;
          }
        }

        for (i = 0; i < 4; i++)
          file.Name[i] = dirpath.Entries[dirpath.NumEntries][i];

        if (!owChangeDirectory(portnum, &AllSN[owd][0], &dirpath)) {
          file_name(&dirpath, &file, FALSE);
          OWERROR_DUMP(stderr);
        } else {
          if (!isJob(portnum, &AllSN[owd][0]))
            owCreateProgramJob(portnum, &AllSN[owd][0]);

          owClearError();

          if (menuSelect(ENTRY_MENU) == MODE_TEXT) {
            len = getData(&data[0], MAX_DATA, FALSE);
          } else {
            len = getData(&data[0], MAX_DATA, TRUE);
          }

          owClearError();
          if (!owOpenFile(portnum, &AllSN[owd][0], &file, &hnd)) {
            error = owGetErrorNum();
            if (error == OWERROR_FILE_NOT_FOUND) {
              if (!owCreateFile(portnum, &AllSN[owd][0], &maxwrite, &hnd, &file)) {
                file_name(&dirpath, &file, TRUE);
                OWERROR_DUMP(stderr);
              } else {
                if (!owOpenFile(portnum, &AllSN[owd][0], &file, &hnd)) {
                  file_name(&dirpath, &file, TRUE);
                  OWERROR_DUMP(stderr);
                } else if (!owWriteFile(portnum, &AllSN[owd][0], hnd, &data[0], len)) {
                  OWERROR_DUMP(stderr);
                }
              }
            } else {
              OWERROR(error);
              OWERROR_DUMP(stderr);
            }
          } else if (!owWriteFile(portnum, &AllSN[owd][0], hnd, &data[0], len)) {
            OWERROR_DUMP(stderr);
          }
        }

        dirpath = owGetCurrentDir(portnum, &AllSN[owd][0]);
        printf("\nThe Current Directory Path is> ");
        if (dirpath.NumEntries == 0)
          printf(" <root> ");
        else {
          for (i = 0; i < dirpath.NumEntries; i++) {
            for (j = 0; j < 4; j++)
              printf("%c", dirpath.Entries[i][j]);
            printf("/");
          }
        }
        printf("\n");

        break;

      case MAIN_READ_FILE:
        printf("Enter the directory and file you would like to read from: ");

        len = getString(&dirname[0]);
        cnt = 0;
        dirpath.NumEntries = 0;

        for (i = 0; i < len; i++) {
          if (dirname[i] != '/') {
            if ((cnt < 4) && (dirname[i] != '.') && isalnum(dirname[i]))
              dirpath.Entries[dirpath.NumEntries][cnt++] = dirname[i];
            else {
              if (dirname[i] == '.') {
                digcnt = 1;
                do {
                  if (isdigit(dirname[i + digcnt])) {
                    num[digcnt - 1] = dirname[i + digcnt];
                    digcnt++;
                  }
                } while (isdigit(dirname[i + digcnt]));

                file.Ext = atoi(&num[0]);
                i = i + digcnt;

                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';
              } else if ((i + 1) == len) {
                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

                cnt = 0;
              }
            }
          } else if (cnt > 0) {
            for (j = cnt; j < 4; j++)
              dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

            dirpath.NumEntries++;
            cnt = 0;
          } else if (dirname[0] == '/') {
            dirpath.NumEntries = 0;
            dirpath.Entries[0][0] = '.';
            dirpath.Entries[0][1] = ' ';
            break;
          }
        }

        for (i = 0; i < 4; i++)
          file.Name[i] = dirpath.Entries[dirpath.NumEntries][i];

        if (!owChangeDirectory(portnum, &AllSN[owd][0], &dirpath)) {
          file_name(&dirpath, &file, FALSE);
          OWERROR_DUMP(stderr);
        } else {
          if (!owOpenFile(portnum, &AllSN[owd][0], &file, &hnd)) {
            file_name(&dirpath, &file, TRUE);
            OWERROR_DUMP(stderr);
          } else if (!owReadFile(portnum, &AllSN[owd][0], hnd, &data[0], MAX_DATA, &len)) {
            OWERROR_DUMP(stderr);
          } else
            for (i = 0; i < len; i++)
              printf("%02X ", data[i]);

          if (!owCloseFile(portnum, &AllSN[owd][0], hnd))
            OWERROR_DUMP(stderr);
        }

        dirpath = owGetCurrentDir(portnum, &AllSN[owd][0]);
        printf("\nThe Current Directory Path is> ");
        if (dirpath.NumEntries == 0)
          printf(" <root> ");
        else {
          for (i = 0; i < dirpath.NumEntries; i++) {
            for (j = 0; j < 4; j++)
              printf("%c", dirpath.Entries[i][j]);
            printf("/");
          }
        }
        printf("\n");

        break;

      case MAIN_DELETE_DIR:
        printf("Enter the directory to delete from <root>  ");

        len = getString(&dirname[0]);
        cnt = 0;
        dirpath.NumEntries = 0;
        for (i = 0; i < len; i++) {
          if (dirname[i] != '/') {
            if ((cnt < 4) && (dirname[i] != '.') && isalnum(dirname[i]))
              dirpath.Entries[dirpath.NumEntries][cnt++] = dirname[i];
            else {
              if (dirname[i] == '.') {
                digcnt = 1;
                do {
                  if (isdigit(dirname[i + digcnt])) {
                    num[digcnt - 1] = dirname[i + digcnt];
                    digcnt++;
                  }
                } while (isdigit(dirname[i + digcnt]));

                file.Ext = atoi(&num[0]);
                i = i + digcnt;

                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';
              } else if ((i + 1) == len) {
                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

                cnt = 0;
              }
            }
          } else if (cnt > 0) {
            for (j = cnt; j < 4; j++)
              dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

            dirpath.NumEntries++;
            cnt = 0;
          } else if (dirname[0] == '/') {
            dirpath.NumEntries = 0;
            dirpath.Entries[0][0] = '.';
            dirpath.Entries[0][1] = ' ';
            break;
          }
        }

        for (i = 0; i < 4; i++)
          file.Name[i] = dirpath.Entries[dirpath.NumEntries][i];
        dirpath.NumEntries++;

        if (!owChangeDirectory(portnum, &AllSN[owd][0], &dirpath)) {
          file_name(&dirpath, &file, FALSE);
          OWERROR_DUMP(stderr);
        } else {
          if (!isJob(portnum, &AllSN[owd][0]))
            owCreateProgramJob(portnum, &AllSN[owd][0]);

          owClearError();

          if (!owRemoveDir(portnum, &AllSN[owd][0], &file))
            OWERROR_DUMP(stderr);
        }

        dirpath = owGetCurrentDir(portnum, &AllSN[owd][0]);
        printf("\nThe Current Directory Path is> ");
        if (dirpath.NumEntries == 0)
          printf(" <root> ");
        else {
          for (i = 0; i < dirpath.NumEntries; i++) {
            for (j = 0; j < 4; j++)
              printf("%c", dirpath.Entries[i][j]);
            printf("/");
          }
        }
        printf("\n");

        break;

      case MAIN_DELETE_FILE:
        printf("Enter the file to delete from <root>  ");

        len = getString(&dirname[0]);
        cnt = 0;
        dirpath.NumEntries = 0;
        for (i = 0; i < len; i++) {
          if (dirname[i] != '/') {
            if ((cnt < 4) && (dirname[i] != '.') && isalnum(dirname[i]))
              dirpath.Entries[dirpath.NumEntries][cnt++] = dirname[i];
            else {
              if (dirname[i] == '.') {
                digcnt = 1;
                do {
                  if (isdigit(dirname[i + digcnt])) {
                    num[digcnt - 1] = dirname[i + digcnt];
                    digcnt++;
                  }
                } while (isdigit(dirname[i + digcnt]));
                num[digcnt - 1] = 0;

                file.Ext = atoi(&num[0]);
                i = i + digcnt;

                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';
              } else if ((i + 1) == len) {
                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

                cnt = 0;
              }
            }
          } else if (cnt > 0) {
            for (j = cnt; j < 4; j++)
              dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

            dirpath.NumEntries++;
            cnt = 0;
          } else if (dirname[0] == '/') {
            dirpath.NumEntries = 0;
            dirpath.Entries[0][0] = '.';
            dirpath.Entries[0][1] = ' ';
            break;
          }
        }

        for (i = 0; i < 4; i++)
          file.Name[i] = dirpath.Entries[dirpath.NumEntries][i];

        if (!owChangeDirectory(portnum, &AllSN[owd][0], &dirpath)) {
          file_name(&dirpath, &file, FALSE);
          OWERROR_DUMP(stderr);
        } else {
          if (!isJob(portnum, &AllSN[owd][0])) {
            owCreateProgramJob(portnum, &AllSN[owd][0]);
            owClearError();
          }

          if (!owDeleteFile(portnum, &AllSN[owd][0], &file))
            OWERROR_DUMP(stderr);
        }

        dirpath = owGetCurrentDir(portnum, &AllSN[owd][0]);
        printf("\nThe Current Directory Path is> ");
        if (dirpath.NumEntries == 0)
          printf(" <root> ");
        else {
          for (i = 0; i < dirpath.NumEntries; i++) {
            for (j = 0; j < 4; j++)
              printf("%c", dirpath.Entries[i][j]);
            printf("/");
          }
        }
        printf("\n");

        break;

      case MAIN_RENAME:
        printf("Enter the file to rename from <root>:  ");

        len = getString(&dirname[0]);
        cnt = 0;
        dirpath.NumEntries = 0;
        for (i = 0; i < len; i++) {
          if (dirname[i] != '/') {
            if ((cnt < 4) && (dirname[i] != '.') && isalnum(dirname[i]))
              dirpath.Entries[dirpath.NumEntries][cnt++] = dirname[i];
            else {
              if (dirname[i] == '.') {
                digcnt = 1;
                do {
                  if (isdigit(dirname[i + digcnt])) {
                    num[digcnt - 1] = dirname[i + digcnt];
                    digcnt++;
                  }
                } while (isdigit(dirname[i + digcnt]));
                num[digcnt - 1] = 0;

                file.Ext = atoi(&num[0]);
                i = i + digcnt;

                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';
              } else if ((i + 1) == len) {
                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

                cnt = 0;
              }
            }
          } else if (cnt > 0) {
            for (j = cnt; j < 4; j++)
              dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

            dirpath.NumEntries++;
            cnt = 0;
          } else if (dirname[0] == '/') {
            dirpath.NumEntries = 0;
            dirpath.Entries[0][0] = '.';
            dirpath.Entries[0][1] = ' ';
            break;
          }
        }

        for (i = 0; i < 4; i++)
          file.Name[i] = dirpath.Entries[dirpath.NumEntries][i];

        if (!owChangeDirectory(portnum, &AllSN[owd][0], &dirpath)) {
          file_name(&dirpath, &file, FALSE);
          OWERROR_DUMP(stderr);
        } else {
          if (!isJob(portnum, &AllSN[owd][0]))
            owCreateProgramJob(portnum, &AllSN[owd][0]);

          owClearError();

          if (!owOpenFile(portnum, &AllSN[owd][0], &file, &hnd)) {
            file_name(&dirpath, &file, TRUE);
            OWERROR_DUMP(stderr);
          } else {
            printf("Enter the name to rename the file: ");
            len = getString(&dirname[0]);
            for (i = 0; i < len; i++) {
              if (dirname[i] == '.') {
                digcnt = 1;
                do {
                  if (isdigit(dirname[i + digcnt])) {
                    num[digcnt - 1] = dirname[i + digcnt];
                    digcnt++;
                  }
                } while (isdigit(dirname[i + digcnt]));
                num[digcnt - 1] = 0;

                file.Ext = atoi(&num[0]);
                i = i + digcnt;
              } else
                file.Name[i] = dirname[i];
            }

            if (!owReNameFile(portnum, &AllSN[owd][0], hnd, &file)) {
              file_name(&dirpath, &file, TRUE);
              OWERROR_DUMP(stderr);
            }

            if (!owCloseFile(portnum, &AllSN[owd][0], hnd))
              OWERROR_DUMP(stderr);
          }
        }

        dirpath = owGetCurrentDir(portnum, &AllSN[owd][0]);
        printf("\nThe Current Directory Path is> ");
        if (dirpath.NumEntries == 0)
          printf(" <root> ");
        else {
          for (i = 0; i < dirpath.NumEntries; i++) {
            for (j = 0; j < 4; j++)
              printf("%c", dirpath.Entries[i][j]);
            printf("/");
          }
        }
        printf("\n");

        break;

      case MAIN_WRITE_ADDFILE:
        if (!isJob(portnum, &AllSN[owd][0])) {
          if (!owCreateProgramJob(portnum, &AllSN[owd][0]))
            OWERROR_DUMP(stderr);
        }

        owClearError();

        printf("Enter the file to addfile to create or append to from <root>:  ");

        len = getString(&dirname[0]);
        cnt = 0;
        dirpath.NumEntries = 0;
        for (i = 0; i < len; i++) {
          if (dirname[i] != '/') {
            if ((cnt < 4) && (dirname[i] != '.') && isalnum(dirname[i]))
              dirpath.Entries[dirpath.NumEntries][cnt++] = dirname[i];
            else {
              if (dirname[i] == '.') {
                digcnt = 1;
                do {
                  if (isdigit(dirname[i + digcnt])) {
                    num[digcnt - 1] = dirname[i + digcnt];
                    digcnt++;
                  }
                } while (isdigit(dirname[i + digcnt]));
                num[digcnt - 1] = 0;

                file.Ext = atoi(&num[0]);
                i = i + digcnt;

                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';
              } else if ((i + 1) == len) {
                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

                cnt = 0;
              }
            }
          } else if (cnt > 0) {
            for (j = cnt; j < 4; j++)
              dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

            dirpath.NumEntries++;
            cnt = 0;
          } else if (dirname[0] == '/') {
            dirpath.NumEntries = 0;
            dirpath.Entries[0][0] = '.';
            dirpath.Entries[0][1] = ' ';
            break;
          }
        }

        for (i = 0; i < 4; i++)
          file.Name[i] = dirpath.Entries[dirpath.NumEntries][i];

        if (!owChangeDirectory(portnum, &AllSN[owd][0], &dirpath)) {
          file_name(&dirpath, &file, FALSE);
          OWERROR_DUMP(stderr);
        } else {
          if (!owOpenFile(portnum, &AllSN[owd][0], &file, &hnd)) {
            owClearError();
            if (!owCreateFile(portnum, &AllSN[owd][0], &maxwrite, &hnd, &file)) {
              file_name(&dirpath, &file, TRUE);
              OWERROR_DUMP(stderr);
            } else
              printf("File was created.\n");
          } else {
            if (menuSelect(ENTRY_MENU) == MODE_TEXT) {
              len = getData(&data[0], MAX_DATA, FALSE);
            } else {
              len = getData(&data[0], MAX_DATA, TRUE);
            }

            printf("Do you want to append this data?\n");
            lentwo = getString(&answer[0]);
            if ((answer[0] == 'Y') || (answer[0] == 'y')) {
              if (!owWriteAddFile(portnum, &AllSN[owd][0], hnd, 1, 0, &data[0], &len))
                OWERROR_DUMP(stderr);

              if (!owCloseFile(portnum, &AllSN[owd][0], hnd))
                OWERROR_DUMP(stderr);

            } else {
              printf("What offset would you like to start writing the data?\n");

              len = getData(&data[0], MAX_DATA, FALSE);

              if (!owWriteAddFile(portnum, &AllSN[owd][0], hnd, 0, answer[0], &data[0], &len))
                OWERROR_DUMP(stderr);

              if (!owCloseFile(portnum, &AllSN[owd][0], hnd))
                OWERROR_DUMP(stderr);
            }
          }
        }

        dirpath = owGetCurrentDir(portnum, &AllSN[owd][0]);
        printf("\nThe Current Directory Path is> ");
        if (dirpath.NumEntries == 0)
          printf(" <root> ");
        else {
          for (i = 0; i < dirpath.NumEntries; i++) {
            for (j = 0; j < 4; j++)
              printf("%c", dirpath.Entries[i][j]);
            printf("/");
          }
        }
        printf("\n");

        break;

      case MAIN_TERMINATE:
        printf("Enter the addfile to terminate from <root>:  ");

        len = getString(&dirname[0]);
        cnt = 0;
        dirpath.NumEntries = 0;
        for (i = 0; i < len; i++) {
          if (dirname[i] != '/') {
            if ((cnt < 4) && (dirname[i] != '.') && isalnum(dirname[i]))
              dirpath.Entries[dirpath.NumEntries][cnt++] = dirname[i];
            else {
              if (dirname[i] == '.') {
                digcnt = 1;
                do {
                  if (isdigit(dirname[i + digcnt])) {
                    num[digcnt - 1] = dirname[i + digcnt];
                    digcnt++;
                  }
                } while (isdigit(dirname[i + digcnt]));
                num[digcnt - 1] = 0;

                file.Ext = atoi(&num[0]);
                i = i + digcnt;

                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';
              } else if ((i + 1) == len) {
                for (j = cnt; j < 4; j++)
                  dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

                cnt = 0;
              }
            }
          } else if (cnt > 0) {
            for (j = cnt; j < 4; j++)
              dirpath.Entries[dirpath.NumEntries][cnt++] = ' ';

            dirpath.NumEntries++;
            cnt = 0;
          } else if (dirname[0] == '/') {
            dirpath.NumEntries = 0;
            dirpath.Entries[0][0] = '.';
            dirpath.Entries[0][1] = ' ';
            break;
          }
        }

        for (i = 0; i < 4; i++)
          file.Name[i] = dirpath.Entries[dirpath.NumEntries][i];

        if (!owChangeDirectory(portnum, &AllSN[owd][0], &dirpath)) {
          file_name(&dirpath, &file, FALSE);
          OWERROR_DUMP(stderr);
        } else {
          if (!owOpenFile(portnum, &AllSN[owd][0], &file, &hnd)) {
            file_name(&dirpath, &file, TRUE);
            OWERROR_DUMP(stderr);
          } else {
            if (!isJob(portnum, &AllSN[owd][0])) {
              if (!owCreateProgramJob(portnum, &AllSN[owd][0]))
                OWERROR_DUMP(stderr);
            }

            owClearError();

            if (!owTerminateAddFile(portnum, &AllSN[owd][0], &file)) {
              OWERROR_DUMP(stderr);
            } else
              printf("File will be terminated once job is programmed.\n");
          }
        }

        break;

      case MAIN_QUIT:
        if (isJob(portnum, &AllSN[owd][0])) {
          printf("Would you like to write the programmed job "
                 "before choosing another button?(Y/N)\n");
          printf("The job will continue and try and write to the \n");
          printf("iButton until it is successful or you hit Ctrl-C.\n");

          len = getString(&answer[0]);

          if ((answer[0] == 'Y') || (answer[0] == 'y')) {
            do {
              if (!owDoProgramJob(portnum, &AllSN[owd][0])) {
                OWERROR_DUMP(stderr);
              } else {
                done = TRUE;
              }
            } while ((!done) || (!key_abort()));
          }
        }

        done = TRUE;
        break;

      default:
        break;

      } // Main menu switch

    } while (!done); // loop to do menu

    owRelease(portnum);
  } // else for owAcquire

  return 1;
}

/**
 * listDir
 *
 * Lists the current files/directories if recursive is FALSE
 * otherwise list all files and directories
 *
 *
 */
void listDir(int portnum, uchar *SNum, FileEntry file, int recursive) {
  int done;
  int i, j;
  DirectoryPath dirpath[10];
  DirectoryPath init;
  int dir_cnt = 0;

  init = owGetCurrentDir(portnum, SNum);

  done = FALSE;
  do {
    done = !owNextFile(portnum, SNum, &file);

    if (file.Name[0] == '.') {
      done = !owNextFile(portnum, SNum, &file);
      if (file.Name[0] == '.')
        done = !owNextFile(portnum, SNum, &file);
    }

    if (!done) {
      if (!(recursive && (file.Ext == 0x7F))) {
        if (recursive) {
          printf("|");
          for (i = 0; i < (4 * init.NumEntries) + 4; i++)
            printf("-");
        }
        for (i = 0; i < 4; i++)
          if (file.Name[i] != ' ')
            printf("%c", file.Name[i]);
      }
      if (file.Ext == 0x7F && !recursive)
        printf("   <dir>\n");
      else if (file.Ext == 0x7F) {
        dirpath[dir_cnt] = owGetCurrentDir(portnum, SNum);
        for (j = 0; j < 4; j++)
          dirpath[dir_cnt].Entries[dirpath[dir_cnt].NumEntries][j] = file.Name[j];
        dirpath[dir_cnt++].NumEntries++;
      } else
        printf(".%03d\n", file.Ext);
    }
  } while (!done);
  done = FALSE;

  for (i = 0; i < dir_cnt; i++) {
    owChangeDirectory(portnum, SNum, &dirpath[i]);

    printf("|");
    for (j = 0; j < (4 * dirpath[i].NumEntries) - 1; j++)
      printf("-");
    printf("|");
    for (j = 0; j < 4; j++)
      file.Name[j] = dirpath[i].Entries[dirpath[i].NumEntries - 1][j];

    for (j = 0; j < 4; j++)
      printf("%c", file.Name[j]);
    printf("\n");
    listDir(portnum, SNum, file, recursive);
  }

  if (dirpath[dir_cnt - 1].NumEntries == 1) {
    dirpath[0].Ref = '0';
    dirpath[0].NumEntries = 0;
    owChangeDirectory(portnum, SNum, &dirpath[0]);
  }

  if (owHasErrors())
    OWERROR_DUMP(stderr);
}

/**
 * Create a menu from the provided OneWireContainer
 * Vector and allow the user to select a device.
 *
 * numDevices  the number of devices on the 1-Wire.
 * AllDevices  holds all the Serial Numbers on the
 *                      1-Wire.
 *
 * @return index of the choosen device.
 */
SMALLINT selectDevice(int numDevices, uchar AllDevices[][8]) {

  int i, j;

  printf("Device Selection\n");

  for (i = 0; i < numDevices; i++) {
    printf("(%d) ", i);
    for (j = 7; j >= 0; j--)
      printf("%02X ", AllDevices[i][j]);
    printf("\n");
  }

  return getNumber(0, numDevices - 1);
}

//--------
//-------- Menu Methods
//--------

/**
 * Display menu and ask for a selection.
 *
 * menu  the menu selections.
 *
 * @return numberic value entered from the console.
 */
int menuSelect(int menu) {
  int length = 0;

  switch (menu) {
  case MAIN_MENU:
    printf("\n");
    printf("----  1-Wire File Shell ----\n");
    printf("(0) Select Device\n");
    printf("(1) Change Directory\n");
    printf("(2) Directory list\n");
    printf("(3) Directory list (recursive)\n");
    printf("(4) Make Directory\n");
    printf("(5) Create empty file \n");
    printf("(6) Write data to a file\n");
    printf("(7) Read data from a file\n");
    printf("(8) Delete 1-Wire directory\n");
    printf("(9) Delete 1-Wire file\n");
    printf("(10) Rename 1-Wire file\n");
    printf("(11) Write or Add to AddFile\n");
    printf("(12) Terminate an AddFile\n");
    printf("(13) Format filesystem on 1-Wire device\n");
    printf("[14]-Quit\n");
    length = 14;
    break;

  case VERIFY_MENU:
    printf("\n");
    printf("Format file system on 1-Wire device?\n");
    printf("(0) NO\n");
    printf("(1) YES (delete all files/directories)\n");
    length = 1;
    break;

  case ENTRY_MENU:
    printf("\n");
    printf("Data Entry Mode\n");
    printf("(0) Text (single line)\n");
    printf("(1) Hex (XX XX XX XX ...)\n");
    length = 1;
    break;
  }

  printf("\nPlease enter value: ");

  return getNumber(0, length);
}

/**
 * Retrieve user input from the console.
 *
 * min  minimum number to accept
 * max  maximum number to accept
 *
 * @return numeric value entered from the console.
 */
int getNumber(int min, int max) {
  int value = min, cnt;
  int done = FALSE;

  do {
    cnt = scanf("%d", &value);
    if (cnt > 0 && (value > max || value < min)) {
      printf("Value (%d) is outside of the limits (%d,%d)\n", value, min, max);
      printf("Try again:\n");
    } else
      done = TRUE;

  } while (!done);

  return value;
}

/**
 * Retrieve user input from the console in the form of hex or text.
 *
 * write_buff  the buffer for the data to be written into.
 *
 * @return length of array
 */
int getString(char *write_buff) {
  char ch;
  int cnt = 0;
  int done = FALSE;

  do {
    ch = (char)getchar();

    if (!isspace(ch))
      write_buff[cnt++] = ch;
    else if ((cnt > 0) && (ch != ' ')) {
      write_buff[cnt++] = 0;
      done = TRUE;
    }
  } while (!done);

  return cnt;
}

//--------
//-------- Display Methods
//--------

/**
 * Display information about the 1-Wire device
 *
 * portnum port number for the device
 * SNum    serial number for the device
 */
void printDeviceInfo(int portnum, uchar SNum[8]) {
  int i;

  printf("\n");
  printf("*************************************************************************\n");
  printf("* Device Name:  %s\n", owGetName(&SNum[0]));
  printf("* Device Address:  ");
  for (i = 7; i >= 0; i--)
    printf("%02X ", SNum[i]);
  printf("\n");
  printf("* iButton Description:  %s\n", owGetDescription(&SNum[0]));
  printf("*************************************************************************\n");
}

/**
 * Display the correct file structure.
 */
void file_name(DirectoryPath *dirpath, FileEntry *file, int inc_filename) {
  int i, j;

  printf("The file format from the root should look like this:\n");
  printf("suba/subb/newf.5\n");

  if (dirpath->NumEntries > 0) {
    printf("This is the path you gave:\n");

    for (i = 0; i < dirpath->NumEntries; i++) {
      for (j = 0; j < 4; j++) {
        if (dirpath->Entries[i][j] != ' ')
          printf("%c", dirpath->Entries[i][j]);
      }
      printf("/\n");
    }
  } else {
    printf("No path was read and if '\\' was the first symbol\n");
    printf("then no path was read and the file name isn't going\n");
    printf("to be valid.\n");
  }

  if (inc_filename) {
    printf("The file name is:\n");

    for (i = 0; i < 4; i++) {
      if (file->Name[i] != ' ')
        printf("%c", file->Name[i]);
    }
    printf("\n");
  }
}
