Skip to content

Instantly share code, notes, and snippets.

@jakewilson801
Last active December 17, 2015 04:39
Show Gist options
  • Save jakewilson801/5552139 to your computer and use it in GitHub Desktop.
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
#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