Browse Source

Initial commit; add, show, help

master
commit
8066c97c5c
  1. 3
      .gitignore
  2. 9
      LICENSE
  3. 10
      Makefile
  4. 33
      README.md
  5. 237
      src/main.c
  6. 188
      src/todo.c
  7. 70
      src/todo.h

3
.gitignore vendored

@ -0,0 +1,3 @@
TODOS.bin
clido
.vscode

9
LICENSE

@ -0,0 +1,9 @@
The MIT License (MIT)
Copyright © 2023 Kasyanov Nikolay Alexeyevich (Unbewohnte)
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 THE AUTHORS OR COPYRIGHT HOLDERS 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.

10
Makefile

@ -0,0 +1,10 @@
all:
gcc -static -O2 -Wall -Werror src/*.c -o clido
clean:
rm -f clido TODOS.bin
install: all
delete:

33
README.md

@ -0,0 +1,33 @@
# clido
## Command Line Interface to DO program
clido helps to keep "to do" notes on the disk space.
## Compilation
Simply `make` or as simply compile .c files together
## Installation
If you're on Linux - `make install` or simply move the binary to ...TODO!!(figure out where to put the binary)
## Usage
`clido [COMMAND]`
Commands:
- `help -> Prints this message and exists`
- `add [todo]... -> Writes a new TODO to a default TODO file`
- `show -> Outputs current TODOs`
- `show-done -> Outputs TODOs which were done previously`
- `done [index OR index1-index2 OR index1,index2] -> Marks specified TODO(s) as done`
## License
![GPLv3](https://www.gnu.org/graphics/gplv3-with-text-84x42.png "GPLv3 logo")
GPLv3

237
src/main.c

@ -0,0 +1,237 @@
/*
The MIT License (MIT)
Copyright © 2023 Kasyanov Nikolay Alexeyevich (Unbewohnte)
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 THE AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "todo.h"
/*
Closes a todo file and frees up memory allocated to store todos, basically
a clean up function.
*/
void clean_up(FILE* todo_file, Todo** todos, size_t todo_count, char* todo_file_path) {
fclose(todo_file);
for (size_t i = 0; i < todo_count; i++) {
todo_delete(&todos[i]);
}
free(todo_file_path);
}
/*
Opens a TODO file for reading and writing at todo_file_path. If an error occurs - creates a new
file instead.
Returns EXIT_FAILURE if creating a new file happens to be unsuccessful or one of the arguments are NULL.
*/
int open_todo_file(const char* todo_file_path, FILE** todo_file) {
if (!todo_file_path || !todo_file) {
return EXIT_FAILURE;
}
*todo_file = fopen(todo_file_path, "r+");
if (!(*todo_file)) {
// Create a new one
printf("[INFO] Failed to read TODO file at \"%s\": %s. Creating a new one...\n", todo_file_path, strerror(errno));
*todo_file = fopen(todo_file_path, "w+");
if (!(*todo_file)) {
fprintf(stderr, "[ERR] Failed to create a new TODO file at the same path: %s\n", strerror(errno));
return EXIT_FAILURE;
}
printf("[INFO] Successfully created a new TODO file\n");
}
return EXIT_SUCCESS;
}
int main(int argc, char** argv) {
char* todo_file_name = "TODOS.bin";
char* todo_file_dir_path = "./";
char* todo_file_path = malloc(sizeof(char) * (strlen(todo_file_dir_path)+strlen(todo_file_name)+1));
todo_file_path = strcat(todo_file_path, todo_file_dir_path);
todo_file_path = strcat(todo_file_path, todo_file_name);
size_t todo_count = 0;
Todo** todos = NULL;
char* arg = NULL;
FILE* todo_file = NULL;
int i = 0;
// Open TODO file
open_todo_file(todo_file_path, &todo_file);
if (argc < 2) {
printf(
"A command is required!\
\nRun clido help to look at usage overview\n"
);
clean_up(todo_file, todos, todo_count, todo_file_path);
return EXIT_FAILURE;
}
// Collect and work out arguments
while (i < argc) {
i++;
arg = argv[i];
// Help command
if (strcmp(arg, "help") == 0 && i == 1) {
printf(
"clido [COMMAND]\
\n\n[COMMAND]:\
\nhelp -> Prints this message and exists\
\nadd [todo] -> Writes a new TODO to a default TODO file\
\nshow -> Outputs current TODOs\
\nshow-done -> Outputs TODOs which were done previously\
\ndone [index OR index1-index2 OR index1,index2] -> Marks specified TODO(s) as done\
\n"
);
clean_up(todo_file, todos, todo_count, todo_file_path);
return EXIT_SUCCESS;
}
// Add command
if (strcmp(arg, "add") == 0) {
i++;
arg = argv[i];
if (i >= argc) {
// No actual text was given
fprintf(stderr, "No TODO text was given!\n");
clean_up(todo_file, todos, todo_count, todo_file_path);
return EXIT_FAILURE;
}
// Todo text will be everything from now on until the end
size_t todo_text_length = 0;
char* todo_text = NULL;
for (size_t j = i; j < argc; j++) {
char* todo_text_part = argv[j];
todo_text_length += strlen(todo_text_part) + 2;
todo_text = (char*) realloc(todo_text, todo_text_length);
todo_text = strcat(todo_text, todo_text_part);
todo_text = strcat(todo_text, " ");
}
Todo* new_todo = todo_new(strlen(todo_text), todo_text);
if (todo_write(todo_file, new_todo) == EXIT_FAILURE) {
fprintf(stderr, "[ERR] Failed to write a new todo: %s\n", strerror(errno));
clean_up(todo_file, todos, todo_count, todo_file_path);
return EXIT_FAILURE;
}
printf("Added!\n");
clean_up(todo_file, todos, todo_count, todo_file_path);
return EXIT_SUCCESS;
}
// Show command
if (strcmp(arg, "show") == 0) {
int result = todos_read(todo_file, &todos, &todo_count);
if (result == EXIT_FAILURE && todo_count == 0) {
printf("No TODOs yet!\n");
return EXIT_SUCCESS;
}
for (size_t j = 0; j < todo_count; j++) {
if (todos[j]->done) {
continue;
}
printf("[%ld] %s\n", j, todos[j]->text);
}
clean_up(todo_file, todos, todo_count, todo_file_path);
return EXIT_SUCCESS;
}
// Show-done command
if (strcmp(arg, "show-done") == 0) {
int result = todos_read(todo_file, &todos, &todo_count);
if (result == EXIT_FAILURE && todo_count == 0) {
printf("No TODOs yet!\n");
return EXIT_SUCCESS;
}
size_t printed = 0;
for (size_t j = 0; j < todo_count; j++) {
if (!todos[j]->done) {
continue;
}
printf("[%ld] %s\n", j, todos[j]->text);
printed++;
}
if (printed == 0) {
printf("No TODOs were done yet!\n");
}
clean_up(todo_file, todos, todo_count, todo_file_path);
return EXIT_SUCCESS;
}
// Done command TODO!!!!!
if (strcmp(arg, "done") == 0) {
int result = todos_read(todo_file, &todos, &todo_count);
if (result == EXIT_FAILURE && todo_count == 0) {
printf("No TODOs yet!\n");
return EXIT_SUCCESS;
}
i++;
if (i >= argc) {
// Not one index was specified
// Mark the first one as DONE
}
arg = argv[i];
for (size_t j = 0; j < todo_count; j++) {
if (todos[j]->done) {
continue;
}
printf("[%ld] %s\n", j, todos[j]->text);
}
clean_up(todo_file, todos, todo_count, todo_file_path);
return EXIT_SUCCESS;
}
}
printf(
"No valid sequence of commands was specified!\
\nRun clido help to look at usage overview\n"
);
clean_up(todo_file, todos, todo_count, todo_file_path);
return EXIT_FAILURE;
}

188
src/todo.c

@ -0,0 +1,188 @@
/*
The MIT License (MIT)
Copyright © 2023 Kasyanov Nikolay Alexeyevich (Unbewohnte)
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 THE AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <error.h>
#include <errno.h>
#include <string.h>
#include <stddef.h>
#include "todo.h"
size_t file_get_size(FILE* file) {
size_t current_pos = 0;
size_t size = 0;
if (file) {
current_pos = ftell(file);
fseek(file, 0, SEEK_END);
size = ftell(file);
fseek(file, current_pos, SEEK_SET);
}
return size;
}
/*
Allocates memory to store a new TODO in it.
Returns a pointer to TODO.
*/
Todo* todo_new(uint32_t text_len, char* text) {
Todo* new_todo = malloc(sizeof(Todo));
if (new_todo) {
new_todo->text_len = text_len;
new_todo->text = text;
}
return new_todo;
}
/*
Frees memory allocated for storing a todo.
Sets pointer to todo to NULL; does nothing if NULL is received
*/
void todo_delete(Todo** todo) {
if (!todo) {
return;
} else if (!*todo) {
return;
}
free((*todo)->text);
free(*todo);
*todo = NULL;
return;
}
/*
Writes a provided todo to a file at current position in binary representation.
Returns EXIT_FAILURE if an error has occured.
*/
int todo_write(FILE* file, const Todo* todo) {
size_t items_written = 0;
if (!file) {
return EXIT_FAILURE;
}
// Append to the end of the file
fseek(file, 0, SEEK_END);
// Text length
items_written = fwrite(&todo->text_len, sizeof(uint32_t), 1, file);
if (items_written != 1) {
return EXIT_FAILURE;
}
// Text
items_written = fwrite(todo->text, sizeof(char), todo->text_len, file);
if (items_written != todo->text_len) {
return EXIT_FAILURE;
}
// Done flag
items_written = fwrite(&todo->done, sizeof(uint8_t), 1, file);
if (items_written != 1) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
/*
Reads the next TODO in provided file, puts it in todo.
Returns EXIT_FAILURE if an error has occured.
*/
int todo_read(FILE* file, Todo* todo) {
size_t read_items = 0;
if (!file || !todo) {
return EXIT_FAILURE;
}
// Read text length
read_items = fread(&todo->text_len, 1, sizeof(uint32_t), file);
if (read_items != sizeof(uint32_t)) {
return EXIT_FAILURE;
}
// Read text
todo->text = malloc(todo->text_len);
read_items = fread(todo->text, 1, todo->text_len, file);
if (read_items != todo->text_len) {
return EXIT_FAILURE;
}
// Read whether it's been done or not
read_items = fread(&todo->done, 1, sizeof(uint8_t), file);
if (read_items != 1) {
return EXIT_FAILURE;
}
if (feof(file)) {
return EXIT_SUCCESS;
}
return EXIT_SUCCESS;
}
/*
Tries to parse TODOs from a given TODO FILE.
todos is a pointer to the beginning of a future TODO array and todos_read
is the amount of TODOs read from file.
Returns EXIT_FAILURE if an error occured somewhere.
*/
int todos_read(FILE* file, Todo*** todos, size_t* todos_read) {
*todos_read = 0;
*todos = NULL;
if (!file) {
return EXIT_FAILURE;
}
while (1) {
Todo* read_todo = todo_new(0, "");
int result = todo_read(file, read_todo);
if (result == EXIT_FAILURE && *todos_read == 0) {
return EXIT_FAILURE;
} else if (result == EXIT_FAILURE && feof(file)) {
break;
}
*todos_read = (*todos_read) + 1;
*todos = realloc(*todos, sizeof(Todo) * (*todos_read));
(*todos)[(*todos_read)-1] = read_todo;
}
return EXIT_SUCCESS;
}
//TODO
int todo_mark_done() {
return EXIT_SUCCESS;
}

70
src/todo.h

@ -0,0 +1,70 @@
/*
The MIT License (MIT)
Copyright © 2023 Kasyanov Nikolay Alexeyevich (Unbewohnte)
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 THE AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
// TODO representation
typedef struct Todo {
uint32_t text_len;
char* text;
uint8_t done;
} Todo;
/*
Allocates memory to store a new TODO in it.
Returns a pointer to TODO.
*/
Todo* todo_new(uint32_t text_len, char* text);
/*
Frees memory allocated for storing a todo.
Sets pointer to todo to NULL; does nothing if NULL is received.
*/
void todo_delete(Todo** todo);
/*
Writes a provided todo to a file at current position in binary representation.
Returns EXIT_FAILURE if an error has occured.
*/
int todo_write(FILE* file, const Todo* todo);
/*
Reads the next TODO in provided file, puts it in todo.
Returns EXIT_FAILURE if an error has occured.
*/
int todo_read(FILE* file, Todo* todo);
/*
Tries to parse TODOs from a given TODO FILE.
todos is a pointer to the beginning of a future TODO array and todos_read
is the amount of TODOs read from file.
Returns EXIT_FAILURE if an error occured somewhere.
*/
int todos_read(FILE* file, Todo*** todos, size_t* todos_read);
//TODO
int todo_mark_done();
Loading…
Cancel
Save