Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
4 changes: 2 additions & 2 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# This file lists all individuals having contributed content to the repository.
# For how it is generated, see `hack/generate-authors.sh`.

Lordwill1 <messagelordwill@gmail.com>
ejilistic <vitalisibeh85@gmail.com>
sadiq Abdulrasheed Bello <sadiqabello0@gmail.com>
Umar Ibrahim <@gmail.com>
184 changes: 70 additions & 114 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,116 +1,72 @@
# 0x16. C - Simple Shell
**By Spencer Cheng, featuring Julien Barbier**
Project to be done in teams of 2 people (your team: Godswill Kalu, Vatalis Ibeh

# Learning Objectives
At the end of this project, you are expected to be able to explain to anyone, without the help of Google:

# General
Who designed and implemented the original Unix operating system
Who wrote the first version of the UNIX shell
Who invented the B programming language (the direct predecessor to the C programming language)
Who is Ken Thompson
How does a shell work
What is a pid and a ppid
How to manipulate the environment of the current process
What is the difference between a function and a system call
How to create processes
What are the three prototypes of main
How does the shell use the PATH to find the programs
How to execute another program with the execve system call
How to suspend the execution of a process until one of its children terminates
What is EOF / “end-of-file”?
# Requirements
# General
Allowed editors: vi, vim, emacs
All your files will be compiled on Ubuntu 20.04 LTS using gcc, using the options -Wall -Werror -Wextra -pedantic -std=gnu89
All your files should end with a new line
A README.md file, at the root of the folder of the project is mandatory
Your code should use the Betty style. It will be checked using betty-style.pl and betty-doc.pl
Your shell should not have any memory leaks
No more than 5 functions per file
All your header files should be include guarded
Use system calls only when you need to (why?)
# GitHub
*There should be one project repository per group. If you and your partner have a repository with the same name in both your accounts, you risk a 0% score. Add your partner as a collaborator. *

More Info
Output
Unless specified otherwise, your program must have the exact same output as sh (/bin/sh) as well as the exact same error output.
The only difference is when you print an error, the name of the program must be equivalent to your argv[0] (See below)
Example of error with sh:

$ echo "qwerty" | /bin/sh
/bin/sh: 1: qwerty: not found
$ echo "qwerty" | /bin/../bin/sh
/bin/../bin/sh: 1: qwerty: not found
$
Same error with your program hsh:

$ echo "qwerty" | ./hsh
./hsh: 1: qwerty: not found
$ echo "qwerty" | ./././hsh
./././hsh: 1: qwerty: not found
$

# List of allowed functions and system calls
access (man 2 access)
chdir (man 2 chdir)
close (man 2 close)
closedir (man 3 closedir)
execve (man 2 execve)
exit (man 3 exit)
_exit (man 2 _exit)
fflush (man 3 fflush)
fork (man 2 fork)
free (man 3 free)
getcwd (man 3 getcwd)
getline (man 3 getline)
getpid (man 2 getpid)
isatty (man 3 isatty)
kill (man 2 kill)
malloc (man 3 malloc)
open (man 2 open)
opendir (man 3 opendir)
perror (man 3 perror)
read (man 2 read)
readdir (man 3 readdir)
signal (man 2 signal)
stat (__xstat) (man 2 stat)
lstat (__lxstat) (man 2 lstat)
fstat (__fxstat) (man 2 fstat)
strtok (man 3 strtok)
wait (man 2 wait)
waitpid (man 2 waitpid)
wait3 (man 2 wait3)
wait4 (man 2 wait4)
write (man 2 write)

# Compilation
## Your shell will be compiled this way:

`gcc -Wall -Werror -Wextra -pedantic -std=gnu89 *.c -o hsh`


# files
- README.md - description about the project repo
- man_1_simple_shell - is the man page for the shell we are going to write.
- AUTHORS - file at the root of your repository, listing all individuals having contributed content to the repository.
- main.h - is the header file which contains the standared header file and prototype of o function used in the program.
- main.c - initialize the program with infinite loop by call the prompt function
- prompt.c - it use getline system call to read the input from the user and run infinite loop with fork to keep prompt going.
- special_character - It identiies if the special inputs such as if the frist input is slash,the user typed exit or env...
- string.c -it handles the strings(string length, write string,find string in directory,concatane strings....)
- cmd.c - it finds the command the user entered.
- execute.c - execute the command.

## How to add Author file
`Bash script for generating the list of authors in git repo`
# GitHub Activity Fetcher

This is a simple C command-line tool to fetch and display a user's public GitHub activity.

## Prerequisites

- `libcurl`: For making HTTP requests.
- `jansson`: For parsing JSON.

On Debian/Ubuntu, you can install these using:
```bash
sudo apt-get update
sudo apt-get install -y libcurl4-openssl-dev libjansson-dev
```

## Building

A build script is provided:
```bash
chmod +x build.sh
./build.sh
```
This will compile `github_activity.c` and create an executable named `github_activity`.

## Usage

```bash
./github_activity <username>
```
#!/bin/sh
Example:
```bash
./github_activity octocat
```

## Testing

First, ensure the program is compiled by running `./build.sh`.

### Automated Basic Test

A simple automated test script is provided to check basic functionality:
```bash
chmod +x test.sh
./test.sh
```
This script currently verifies the "No arguments" test case.

### Manual Test Cases

**Test Case 1: No arguments.**
* Command: `./github_activity`
* Expected Output: Error message "Usage: github_activity <username>" printed to stderr, and the program should exit with a non-zero status code (e.g., 1).

**Test Case 2: Valid username.**
* Command: `./github_activity octocat`
* Expected Output: A list of recent public events for 'octocat'. Each event should be displayed in the format: "Event Type: [Event Type], Repository: [Repository Name], Time: [Timestamp]".
* Example: `Fetching activity for user: octocat`
* `Event Type: PushEvent, Repository: octocat/Spoon-Knife, Time: 2023-10-27T12:34:56Z` (The exact events and timestamps will vary).

**Test Case 3: Invalid/Non-existent username.**
* Command: `./github_activity NonExistentUser12345xyzAbc`
* Expected Output: The program should indicate that no events were found or the user is invalid.
* Example: `Fetching activity for user: NonExistentUser12345xyzAbc`
* Followed by either no event output, or an API error message like "JSON error on line 1: '{' expected near end of file" if the API returns an error document (e.g. `{"message":"Not Found", ...}`).

git shortlog -se \
| perl -spe 's/^\s+\d+\s+//' \
| sed -e '/^CommitSyncScript.*$/d' \
> AUTHORS
```
**Test Case 4: Network Error Simulation.**
* Instruction: Disconnect your machine from the internet (e.g., turn off Wi-Fi or unplug the Ethernet cable).
* Command: `./github_activity octocat`
* Expected Output: A cURL error message should be printed to stderr.
* Example: `Fetching activity for user: octocat`
* `curl_easy_perform() failed: Couldn't resolve host name` (or similar network-related cURL error).
(Remember to reconnect to the internet after this test.)
8 changes: 8 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

# This script compiles github_activity.c and links it with libcurl and jansson.
# -o github_activity: Specifies the output executable name.
# github_activity.c: The source file to compile.
# -lcurl: Links with the libcurl library.
# -ljansson: Links with the libjansson library.
gcc -o github_activity github_activity.c -lcurl -ljansson
130 changes: 130 additions & 0 deletions github_activity.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <jansson.h>

struct MemoryStruct {
char *memory;
size_t size;
};

// Callback function to handle writing received data
static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;

char *ptr = realloc(mem->memory, mem->size + realsize + 1);
if(ptr == NULL) {
/* out of memory! */
fprintf(stderr, "not enough memory (realloc returned NULL)\n");
return 0;
}

mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;

return realsize;
}

void fetch_user_activity(const char *username) {
CURL *curl;
CURLcode res;
char *url = NULL;
const char *base_url = "https://api.github.com/users/";
const char *events_suffix = "/events/public";

struct MemoryStruct chunk;
chunk.memory = malloc(1); /* will be grown as needed by the realloc above */
if(chunk.memory == NULL) {
fprintf(stderr, "Failed to allocate memory for chunk\n");
return;
}
chunk.size = 0; /* no data at this point */
chunk.memory[0] = '\0';

// Calculate the length of the URL
size_t url_len = strlen(base_url) + strlen(username) + strlen(events_suffix) + 1;
url = malloc(url_len);
if (url == NULL) {
fprintf(stderr, "Failed to allocate memory for URL\n");
free(chunk.memory);
return;
}
// Construct the URL
snprintf(url, url_len, "%s%s%s", base_url, username, events_suffix);

curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "github-activity-c-tool/1.0");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);

res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
} else {
json_t *root;
json_error_t error;
root = json_loads(chunk.memory, 0, &error);

if (!root) {
fprintf(stderr, "JSON error on line %d: %s\n", error.line, error.text);
} else {
if (!json_is_array(root)) {
fprintf(stderr, "Error: root is not a JSON array.\n");
} else {
for (size_t i = 0; i < json_array_size(root); i++) {
json_t *event = json_array_get(root, i);
if (!event || !json_is_object(event)) {
fprintf(stderr, "Error: event is not a JSON object.\n");
continue;
}

const char *type_str = "N/A";
json_t *type_json = json_object_get(event, "type");
if (type_json && json_is_string(type_json)) {
type_str = json_string_value(type_json);
}

const char *repo_name_str = "N/A";
json_t *repo_obj = json_object_get(event, "repo");
if (repo_obj && json_is_object(repo_obj)) {
json_t *repo_name_json = json_object_get(repo_obj, "name");
if (repo_name_json && json_is_string(repo_name_json)) {
repo_name_str = json_string_value(repo_name_json);
}
}

const char *created_at_str = "N/A";
json_t *created_at_json = json_object_get(event, "created_at");
if (created_at_json && json_is_string(created_at_json)) {
created_at_str = json_string_value(created_at_json);
}
printf("Event Type: %s, Repository: %s, Time: %s\n", type_str, repo_name_str, created_at_str);
}
}
json_decref(root);
}
}
curl_easy_cleanup(curl);
} else {
fprintf(stderr, "Failed to initialize CURL\n");
}
free(url);
free(chunk.memory);
}

int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: github_activity <username>\n");
return 1;
}
char *username = argv[1];
printf("Fetching activity for user: %s\n", username);
fetch_user_activity(username);
return 0;
}
23 changes: 23 additions & 0 deletions test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash
echo "Running tests..."

# Ensure the program is built
./build.sh
if [ ! -f ./github_activity ]; then
echo "Build failed, cannot run tests."
exit 1
fi

echo "Test Case 1: No arguments"
OUTPUT_NO_ARGS=$(./github_activity 2>&1) # Capture both stdout and stderr
EXIT_CODE_NO_ARGS=$?

# Check exit code (should be non-zero, e.g. 1 as implemented)
# Check stderr for usage message (as implemented)
if [ $EXIT_CODE_NO_ARGS -ne 0 ] && echo "$OUTPUT_NO_ARGS" | grep -q "Usage: github_activity <username>"; then
echo " PASSED: Correct exit code and usage message."
else
echo " FAILED: Expected non-zero exit code and usage message. Got exit code $EXIT_CODE_NO_ARGS and output: $OUTPUT_NO_ARGS"
fi

echo "Basic tests complete. Please perform manual tests as described in README.md."