Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions implement-shell-tools/cat/cat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const fs = require("fs");

//
// ===== cat Procedure =====
function cat(args) {
const userArgs = args.slice(2);
const currentWorkingDirectory = getCurrentWorkingDirectory(args);
const fileNames = getFileNames(userArgs, currentWorkingDirectory);

const allFilesContents = readFiles(fileNames, currentWorkingDirectory);
executeFlags(getFlags(userArgs), allFilesContents);
printLines(allFilesContents);
}

//
// ===== Extracting Data From Arguments =====
function getCurrentWorkingDirectory(args) {
const index = args[1].lastIndexOf("/");
return args[1].slice(0, index + 1);
}

function getFileNames(userArgs) {
return userArgs.filter((argument) => !argument.startsWith("-"));
}

function readFiles(fileNames, currentWorkingDirectory) {
const allFilesContents = [];
fileNames.forEach((fileName) => {
fileContent = readFile(fileName, currentWorkingDirectory);
allFilesContents.push(fileContent.split("\n"));
});
return allFilesContents;
}

function readFile(fileName, currentWorkingDirectory) {
const filePath = currentWorkingDirectory + fileName;
return fs.readFileSync(filePath, "utf8").trimEnd();
}

//
// ===== Flag Handling =====
const flagHandlers = {
b: bFlag,
n: nFlag,
};

function getFlags(userArgs) {
return userArgs
.filter((arg) => arg.startsWith("-"))
.map((arg) => arg.slice(1))
.join("");
}

function executeFlags(flags, allFilesContents) {
for (const flag of flags) {
if (flagHandlers[flag]) flagHandlers[flag](allFilesContents, flags);
else invalidFlagError();
}
}

function invalidFlagError() {
console.error(`cat: illegal option -- ${flag}\nusage: cat [-belnstuv] [file ...]`);
process.exit(1);
}

function bFlag(allFilesContents) {
let linenumber = 1;
allFilesContents.forEach((fileContent) => {
fileContent.forEach((line, index) => {
if (line !== "") {
fileContent[index] = `${String(linenumber).padStart(6, " ")} ${line}`;
linenumber += 1;
}
});
});
}

function nFlag(allFilesContents, flags) {
if (!flags.includes("b")) {
allFilesContents.forEach((fileContent) => {
fileContent.forEach((line, index) => (fileContent[index] = `${String(index + 1).padStart(6, " ")} ${line}`));
});
}
}

//
// ==== Print Output =====
function printLines(allFilesContents) {
allFilesContents.forEach((fileContent) => {
fileContent.forEach((line) => {
console.log(line);
});
});
}

//
// ===== Run cat =====
cat(process.argv);
140 changes: 140 additions & 0 deletions implement-shell-tools/ls/ls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
const fs = require("fs");
const { allowedNodeEnvironmentFlags } = require("process");

//
// ===== ls Procedure =====
function ls(args) {
const userArgs = args.slice(2);

executeFlags(getFlags(userArgs));

const currentWorkingDirectory = getCurrentWorkingDirectory(args);
const fsItems = checkArgsLength(getFsItems(userArgs));
const dirArgs = getDirArgs(currentWorkingDirectory, fsItems);
const fileArgs = getFileArgs(currentWorkingDirectory, fsItems);

print(populateOutput(currentWorkingDirectory, fsItems, dirArgs, fileArgs));
}

//
// ===== Flag Handling =====
const flagHandlers = {
1: Flag1,
a: Flaga,
};

let printInList = false;
let showAll = false;

function getFlags(userArgs) {
return userArgs
.filter((arg) => arg.startsWith("-"))
.map((arg) => arg.slice(1))
.join("");
}

function executeFlags(flags) {
for (const flag of flags) {
if (flagHandlers[flag]) flagHandlers[flag]();
else invalidFlagError();
}
}

function invalidFlagError() {
console.error(
`ls: invalid option -- ${flag}\nusage: ls [-@ABCFGHILOPRSTUWXabcdefghiklmnopqrstuvwxy1%,] [--color=when] [-D format] [file ...]`,
);
process.exit(1);
}

function Flag1() {
printInList = true;
}

function makeList(outputString) {
return outputString.replaceAll("\t", "\n").replaceAll("\n\n", "\n");
}

function Flaga() {
showAll = true;
}

//
// ===== Extracting Data From Arguments =====
function getCurrentWorkingDirectory(args) {
const index = args[1].lastIndexOf("/");
return args[1].slice(0, index + 1);
}

function getFsItems(userArgs) {
return userArgs.filter((arg) => !arg.startsWith("-"));
}

function checkArgsLength(fsItems) {
if (fsItems.length == 0) fsItems.push(".");
return fsItems;
}

function getDirArgs(currentWorkingDirectory, fsItems) {
return fsItems.filter((p) => fs.statSync(currentWorkingDirectory + p).isDirectory());
}

function getFileArgs(currentWorkingDirectory, fsItems) {
const fileArgs = fsItems.filter((p) => !fs.statSync(currentWorkingDirectory + p).isDirectory());
if (showAll == false) removeDotFiles(fileArgs);
return fileArgs;
}

//
// ===== Populating and Outputting Data =====
function populateOutput(currentWorkingDirectory, fsItems, dirArgs, fileArgs) {
let outputString = "";
if (fsItems.length == 1) {
fileArgs.forEach((file) => {
outputString += file + " ";
});
dirArgs.forEach((dir) => {
outputString += dirOutput(dir, currentWorkingDirectory);
});
} else {
fileArgs.forEach((file) => {
outputString += file + "\t";
});
dirArgs.forEach((dir) => {
outputString += "\n\n" + dir + ":\n" + dirOutput(dir, currentWorkingDirectory);
});
}
return outputString;
}

function dirOutput(dir, currentWorkingDirectory) {
let contents = fs.readdirSync(currentWorkingDirectory + dir);
let outputStr = "";
if (showAll) outputStr += ".\t..\t";
else {
for (let i = contents.length - 1; i >= 0; i--) {
contents = removeDotFiles(contents);
}
}
contents.forEach((item) => {
outputStr += item + "\t";
});
return outputStr;
}

function removeDotFiles(fileList) {
for (let i = fileList.length - 1; i >= 0; i--) {
if (fileList[i][0] == ".") fileList.splice(i, 1);
}
return fileList;
}

function print(outputString) {
let output = outputString;
if (printInList) output = makeList(output);
console.log(output.trimEnd());
}

//
// ===== Run ls =====
ls(process.argv);
139 changes: 139 additions & 0 deletions implement-shell-tools/wc/wc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
const fs = require("fs");
const { allowedNodeEnvironmentFlags } = require("process");

const metrics = ["lineCount", "wordCount", "byteSize"];
const displayedMetrics = [];

//
// ===== wc Procedure =====
function wc(args) {
const userArgs = args.slice(2);

executeFlags(getFlags(userArgs));

const currentWorkingDirectory = getCurrentWorkingDirectory(args);
const fileNames = getFileNames(userArgs);

const allFilesData = addTotals(extractFilesData(fileNames, currentWorkingDirectory));
printOutput(allFilesData);
}

//
// ===== Flag Handling =====
const flagHandlers = {
l: lFlag,
w: wFlag,
c: cFlag,
};

function getFlags(userArgs) {
return userArgs
.filter((arg) => arg.startsWith("-"))
.map((arg) => arg.slice(1))
.join("");
}

function executeFlags(flags, allFilesData) {
for (const flag of flags) {
if (flagHandlers[flag]) flagHandlers[flag](allFilesData);
else invalidFlagError();
}
}

function invalidFlagError() {
console.error(`wc: illegal option -- ${flag}\nusage: wc [-Lclmw] [file ...]`);
process.exit(1);
}

function lFlag() {
displayedMetrics.push("lineCount");
}

function wFlag() {
displayedMetrics.push("wordCount");
}

function cFlag() {
displayedMetrics.push("byteSize");
}

//
// ===== Extracting Data From Arguments =====
function getCurrentWorkingDirectory(args) {
const index = args[1].lastIndexOf("/");
return args[1].slice(0, index + 1);
}

function getFileNames(userArgs) {
return userArgs.filter((argument) => !argument.startsWith("-"));
}

//
// ===== Extracting Files Data =====
function extractFilesData(fileNames, currentWorkingDirectory) {
const allFilesData = [];

fileNames.forEach((fileName) => {
const fileData = {};
fileData.name = fileName;
fileData.text = readFile(fileName, currentWorkingDirectory);
fileData.lineCount = calculateLineCount(fileData.text);
fileData.wordCount = calculateWordCount(fileData.text);
fileData.byteSize = readByteSize(fileName, currentWorkingDirectory);

allFilesData.push(fileData);
});
return allFilesData;
}

function readFile(fileName, currentWorkingDirectory) {
const filePath = currentWorkingDirectory + fileName;
return fs.readFileSync(filePath, "utf8").trimEnd();
}

function calculateLineCount(text) {
return text.split("\n").length;
}

function calculateWordCount(text) {
return text.split(/\s+/).length;
}

function readByteSize(fileName, currentWorkingDirectory) {
return fs.statSync(currentWorkingDirectory + fileName).size;
}

function addTotals(allFilesData) {
if (allFilesData.length == 1) return allFilesData;

const totalsData = { name: "total" };
metrics.forEach((metric) => {
let sum = 0;
allFilesData.forEach((file) => {
sum += file[metric];
});
totalsData[metric] = sum;
});
allFilesData.push(totalsData);
return allFilesData;
}

//
// ===== Outputting Data =====
function printOutput(outputData) {
outputData.forEach((file) => {
let outputString = "";
metrics.forEach((metric) => {
if (displayedMetrics.length === 0 || displayedMetrics.includes(metric)) {
outputString += String(file[metric]).padStart(8, " ");
}
});

outputString += ` ${file.name}`;
console.log(outputString);
});
}

//
// ===== Run wc =====
wc(process.argv);