Last active
December 17, 2015 04:39
-
-
Save jakewilson801/5552139 to your computer and use it in GitHub Desktop.
An amazing command line built in c++ for an Operating Systems class in school
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "wsh.h" | |
#include <iostream> | |
#include <fstream> | |
#include <string> | |
#include <cstring> | |
#include <map> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <sys/stat.h> | |
#include <sys/types.h> | |
#include <dirent.h> | |
using namespace std; | |
// used to convert numeric file modes to string representation | |
char* fmodes[] = { "---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx" }; | |
// ----------------------------------------------------------------------------------- | |
wsh::wsh() | |
{ | |
char* commands[] = { "-place holder-", "exit", "copy", "cd", "list", | |
"view", "del", "ren", "mkdir", "rmdir" }; | |
for (unsigned i = 1; i < sizeof(commands)/sizeof(char*); i++) | |
command_table[commands[i]] = i; | |
system("clear"); | |
getcwd(cwd, PATH_MAX); | |
} | |
int wsh::next_command() | |
{ | |
// LAB 1: place assignment code here. | |
// Note that the program will not run until this part is completed. | |
// define a command buffer and a place for the current working directory string | |
static char cmd[PATH_MAX]; | |
char *token; | |
// display current working directory | |
cout << cwd; | |
cout << "=>"; | |
// get a command and arguments from the user, count and parse into argv[] | |
cin.getline(cmd, sizeof(cmd)); | |
// reset argc | |
argc = 0; | |
// while tokens available, assign them to argv using argc as index | |
token = strtok(cmd, " \t"); | |
while (token != NULL) { | |
argv[argc++] = token; | |
token = strtok(NULL, " \t"); | |
} | |
// if there were no tokens, return NONE else return token from ENUM | |
if (argv[0] == NULL) | |
return NONE; | |
else | |
return command_table[argv[0]]; | |
} | |
void wsh::interpret() // loops executing commands from the command line. | |
{ | |
bool running = true; | |
while (running) | |
{ | |
int c = next_command(); | |
switch(c) | |
{ | |
case EXIT : | |
running = false; | |
break; | |
case COPY : | |
copy(); | |
break; | |
case CD : | |
cd(); | |
break; | |
case LIST : | |
list(); | |
cout << endl; | |
break; | |
case VIEW : | |
view(); | |
break; | |
case DEL : | |
del(); | |
break; | |
case REN : | |
ren(); | |
break; | |
case MKDIR : | |
makedir(); | |
break; | |
case RMDIR : | |
removedir(); | |
break; | |
case NONE : | |
break; | |
default: | |
for (int i = 0; i < argc && argv[i] != NULL; i++) | |
cout << argv[i] << endl; | |
break; | |
} | |
} | |
} | |
// where the actual listing happens | |
bool wsh::list(const bool recursive, const bool detailed, char source[]) | |
{ | |
bool success = true; | |
DIR *dir; | |
struct dirent *dirEntry; | |
struct stat statbuf; | |
char path[PATH_MAX]; | |
// assign dir | |
if (!(dir = opendir(source))){ | |
cout << "error finding " << source << endl; | |
return -1; | |
} | |
strcpy(path, source); | |
// now, start copying the files. | |
while (dirEntry = readdir(dir)){ | |
// Ran into a subdirectory? | |
if (dirEntry->d_type & DT_DIR && recursive) { | |
if (!strcmp(dirEntry->d_name, ".")){ | |
continue; | |
} | |
if (!strcmp(dirEntry->d_name, "..")) | |
continue; | |
strcat(path, "/"); | |
strcat(path, dirEntry->d_name); | |
success = list(recursive, detailed, path); | |
if (!success) { | |
return false; | |
} | |
if (detailed) | |
cout << getListLong(dirEntry->d_name) << endl; | |
else | |
cout << getListShort(dirEntry->d_name) << endl; | |
strcpy(path, source); | |
} | |
// else, list | |
else { | |
if (detailed) | |
cout << getListLong(dirEntry->d_name) << endl; | |
else | |
cout << getListShort(dirEntry->d_name) << endl; | |
} | |
} | |
return success; | |
} | |
char* wsh::getListShort(char source[]) | |
{ | |
char result[PATH_MAX]; | |
struct stat buf; | |
strcpy(result, source); | |
stat(source, &buf); | |
// directory | |
if (S_ISDIR(buf.st_mode)) | |
strcat(result, "/"); | |
// executable | |
else if ((buf.st_mode & S_IEXEC) != 0) | |
strcat(result, "*"); | |
// if none of these, it's just a regular file. No modifications. | |
return result; | |
} | |
char* wsh::getListLong(char source[]) | |
{ | |
const int bufferSize = 11; | |
struct stat buf; | |
char result[PATH_MAX]; | |
char buffer[bufferSize]; | |
stat(source, &buf); | |
// permissions | |
strcat(result, (S_ISDIR(buf.st_mode)) ? "d" : "-"); | |
strcat(result, (buf.st_mode & S_IRUSR) ? "r" : "-"); | |
strcat(result, (buf.st_mode & S_IWUSR) ? "w" : "-"); | |
strcat(result, (buf.st_mode & S_IXUSR) ? "x" : "-"); | |
strcat(result, (buf.st_mode & S_IRGRP) ? "r" : "-"); | |
strcat(result, (buf.st_mode & S_IWGRP) ? "w" : "-"); | |
strcat(result, (buf.st_mode & S_IXGRP) ? "x" : "-"); | |
strcat(result, (buf.st_mode & S_IROTH) ? "r" : "-"); | |
strcat(result, (buf.st_mode & S_IWOTH) ? "w" : "-"); | |
strcat(result, (buf.st_mode & S_IXOTH) ? "x" : "-"); | |
// file size | |
sprintf(buffer, "%*d", bufferSize, (int)buf.st_size); | |
strcat(result, buffer); | |
// date modified, time modified | |
struct tm *t = localtime(&buf.st_mtime); | |
sprintf(buffer, " %02d/%02d/%04d %02d:%02d:%02d ", | |
t->tm_mon+1, | |
t->tm_mday, | |
t->tm_year+1900, | |
t->tm_hour, | |
t->tm_min, | |
t->tm_sec); | |
strcat(result, buffer); | |
strcat(result, source); | |
strcat(result, "\n"); | |
return result; | |
} | |
void wsh::list() | |
{ | |
bool recursive = false; | |
bool detailed = false; | |
char path[PATH_MAX]; | |
if (argc > 4){ | |
cout << "Invalid arguements for list" << endl; | |
return; | |
} | |
// decide how to handle list (-s, -l, etc) | |
if (argc == 3 || argc == 4){ | |
if (argv[1][1] == 's') | |
recursive = true; | |
else if (argv[1][1] == 'l') | |
detailed = true; | |
if (argv[2][1] == 's') | |
recursive = true; | |
else if (argv[2][1] == 'l') | |
detailed = true; | |
// check for two next to each other | |
if (argv[1][2] == 's') | |
recursive = true; | |
else if (argv[1][2] == 'l') | |
detailed = true; | |
} | |
// if there are 2 args, check all for switches | |
else if (argc == 2){ | |
if (argv[1][1] == 's') | |
recursive = true; | |
else if (argv[1][1] == 'l') | |
detailed = true; | |
// check for two next to each other | |
if (argv[1][2] == 's') | |
recursive = true; | |
else if (argv[1][2] == 'l') | |
detailed = true; | |
} | |
// assign path | |
if (argc == 1 || argc == 2 && recursive || detailed) | |
strcpy(path, cwd); | |
else if (argc == 3) | |
strcpy(path, argv[2]); | |
else if (argc == 4) | |
strcpy(path, argv[3]); | |
list(recursive, detailed, path); | |
//cout << getListLong(statbuf, argv[1]) << endl; | |
} | |
void wsh:: view() | |
{ | |
if(argc != 2) | |
cout << "Invalid args for view" <<endl; | |
string line; | |
ifstream myfile (argv[1]); | |
if (myfile.is_open()) | |
{ | |
while ( myfile.good() ) | |
{ | |
getline (myfile,line); | |
cout << line << endl; | |
} | |
myfile.close(); | |
} | |
else cout << "Unable to open file"; | |
} | |
// TODO: add error checking | |
void wsh::ren() | |
{ | |
// Valid arguments? | |
if (argc != 3){ | |
cout << "Invalid arguments to ren\n"; | |
return; | |
} | |
if (rename(argv[1], argv[2])){ | |
cout << "Unable to rename" << argv[1] << "\n"; | |
return; | |
} | |
} | |
// copy single | |
bool wsh::copy(const char *source, const char *destination) | |
{ | |
bool success = false; | |
// reading selected file in without modifying it. | |
// using binary stream in case it's not just text. | |
fstream::pos_type size; | |
ifstream input (source, ios::in|ios::binary|ios::ate); | |
char *memBlock; | |
// read file into stream | |
if (input.is_open()){ | |
size = input.tellg(); | |
memBlock = new char [size]; | |
input.seekg (0, ios::beg); | |
input.read (memBlock, size); | |
input.close(); | |
} | |
// now write the file stream to different location | |
ofstream output (destination, ios::out|ios::binary); | |
if (output.is_open()){ | |
output.write(memBlock, size); | |
output.close(); | |
success = true; | |
} | |
else | |
cout << "Error writing file" << destination << "\n"; | |
return success; | |
} | |
// decide how to handle copy command | |
void wsh::copy() | |
{ | |
char *destination; | |
DIR *dir; | |
struct dirent *dirEntry; | |
// Needs 3 args (command called, file/dir to copy, file/dir destination | |
if (argc != 3) { | |
cout << "Invalid arguments to copy\n"; | |
return; | |
} | |
// current directory? | |
if (argv[argc - 1][0] == '.' && strlen(argv[argc - 1]) == 1) | |
destination = strrchr(argv[argc - 2], '\\'); | |
else | |
destination = argv[argc - 1]; | |
// are we looking at a directory? recursively copy | |
if(dir = opendir(argv[argc - 2])) | |
{ | |
//Need to keep track of source directory | |
char sourcePath[PATH_MAX]; | |
//Is the destination path a full path? | |
strcpy(sourcePath, cwd); | |
strcat(sourcePath, "/"); | |
strcat(sourcePath, argv[argc - 2]); | |
char destinationPath[PATH_MAX]; | |
if (argv[argc - 1][0] == '/'){ | |
strcpy(destinationPath, destination); | |
strcat(destinationPath, "/"); | |
strcat(destinationPath, argv[argc - 2]); | |
//destinationPath[strlen(destinationPath) - 1] = NULL; | |
cout << destination << " Destination path \n"; | |
} | |
else{ | |
strcpy(destinationPath, cwd); | |
strcat(destinationPath, "/"); | |
strcat(destinationPath, destination); | |
} | |
mkdir(destinationPath, 0700); | |
// now, chdir inside source directory | |
if (chdir(argv[argc - 2])){ | |
cout << "Unhandled error\n"; | |
return; | |
} | |
// now, start copying the files. | |
while (dirEntry = readdir(dir)){ | |
destination = dirEntry->d_name; | |
// Ran into a subdirectory? | |
if (dirEntry->d_type & DT_DIR) { | |
// skip "." and ".." | |
if (!strcmp(dirEntry->d_name, ".")) | |
continue; | |
if (!strcmp(dirEntry->d_name, "..")) | |
continue; | |
// keeping track of source's path | |
strcat(sourcePath, "/"); | |
strcat(sourcePath, destination); | |
// destationPath | |
strcat(destinationPath, "/"); | |
strcat(destinationPath, destination); | |
// mkdir inside destination called source | |
mkdir(destinationPath, 0700); | |
// now, chdir inside source directory | |
if (chdir(sourcePath) || !(dir = opendir(sourcePath))){ | |
cout << "Unhandled error\n"; | |
return; | |
} | |
} | |
// else, send to copy | |
else { | |
char filePath[PATH_MAX]; | |
strcpy(filePath, destinationPath); | |
strcat(filePath, "/"); | |
strcat(filePath, destination); | |
if (!copy(dirEntry->d_name, filePath)){ | |
cout << "Error copying " << destination << "\n"; | |
return; | |
} | |
} | |
} | |
} | |
// If not recursive, just copy | |
else if (!copy(argv[argc -2], destination)){ | |
perror(argv[argc - 2]); | |
return; | |
} | |
} | |
void wsh::cd() | |
{ | |
char *newDir = argv[1]; | |
if (argc != 2){ | |
cout << "Invalid arguements for CD\n"; | |
} | |
else if (strcmp(argv[1], "..") == 0){ | |
int count = 0; | |
int marker = 0; | |
while (cwd[count] != NULL){ | |
if (cwd[count] == '/') | |
marker = count; | |
count++; | |
} | |
cwd[marker] = NULL; | |
chdir(cwd); | |
getcwd(cwd, PATH_MAX); | |
} | |
else if (chdir(newDir) == -1){ | |
cout << "No such directory\n"; | |
return; | |
} | |
else{ | |
chdir(newDir); | |
getcwd(cwd, PATH_MAX); | |
} | |
} | |
void wsh::del() | |
{ | |
if (remove(argv[1])) | |
perror(argv[1]); | |
} | |
void wsh::removedir() | |
{ | |
// verify 2 or 3 arguments only | |
if (argc != 2 && argc != 3) { | |
cout << "Invalid arguments to rmdir"; | |
return; | |
} | |
// 3 args means rmdir -s DIR: verify the -s and recursively delete everything | |
if (argc == 3) { | |
if (strcmp(argv[1], "-s")) { | |
cout << "Invalid arguments to rmdir"; | |
return; | |
} | |
// call a recursive algorithm to delete everything inside a dir plus the dir itself | |
if (!removedir(argv[2])) { | |
cout << "Failure deleting " << argv[2] << endl; | |
} | |
return; | |
} | |
// -s not specified, simply remove the directory | |
if (rmdir(argv[1])) { | |
perror(argv[1]); | |
} | |
} | |
void wsh::makedir(){ | |
if(argc != 2){ | |
cout << "Invalid arguement to mkdir" << endl; | |
return; | |
} | |
if(chdir(argv[1])){ | |
cout << "Directory already exists" << endl; | |
return; | |
} | |
mkdir(argv[1], 0700); | |
} | |
bool wsh::removedir(char *dirName) | |
{ | |
DIR *dir; | |
struct dirent *dirEntry; | |
bool success; | |
int rc; | |
cout << "processing subdirectory " << dirName << endl; | |
if (!(dir = opendir(dirName))) { | |
perror(dirName); | |
return false; | |
} | |
// chdir into directory to process its entries | |
cout << "chdir into " << dirName << endl; | |
int temp = chdir(dirName); | |
while ((dirEntry = readdir(dir))) { | |
// if a directory found, recurse to delete everything in it | |
if (dirEntry->d_type & DT_DIR) { | |
// skip "." and ".." | |
if (!strcmp(dirEntry->d_name, ".")) | |
continue; | |
if (!strcmp(dirEntry->d_name, "..")) | |
continue; | |
cout << "found subdirectory " << dirEntry->d_name << endl; | |
success = removedir(dirEntry->d_name); | |
if (!success) { | |
return false; | |
} | |
} else { | |
// otherwise delete the entry | |
cout << "deleting " << dirEntry->d_name << endl; | |
// success = true; | |
rc = remove(dirEntry->d_name); | |
if (rc) { | |
perror(dirEntry->d_name); | |
return false; | |
} | |
} | |
} | |
// director is now empty -- chdir out of it and delete it | |
cout << "chdir out of " << dirName << endl; | |
chdir(".."); | |
cout << "deleting " << dirName << endl; | |
// success = true; | |
rc = rmdir(dirName); | |
if (rc) { | |
perror(dirName); | |
return false; | |
} | |
return true; | |
} | |
int main() // execution startup. | |
{ | |
wsh cli; | |
cli.interpret(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment