diff --git a/Makefile b/Makefile
index bd1837442555a07d42035c231a90e1aa63618830..64348f9a873f078dcc57306cce2c36ea757d47c6 100644
--- a/Makefile
+++ b/Makefile
@@ -8,28 +8,24 @@ LIBS = -lssl -lcrypto
 BIN = bin
 
 # Get source and object
-SRCS = $(filter-out $(wildcard mdtest.c), $(wildcard *.c */*.c))
+SRCS = $(filter-out mdtest.c, $(wildcard *.c */*.c))
 OBJS = $(addprefix $(BIN)/, $(SRCS:.c=.o))
-SRCS_TEST = $(filter-out $(wildcard main.c */main.c gfx/*), $(wildcard *.c */*.c))
-OBJS_TEST = $(addprefix $(BIN)/, $(SRCS_TEST:.c=.o))
+
+.PHONY: digest libdigest all clean
 
 # Create the target
-main: $(OBJS)
-	$(CC) $(CFLAGS) -o $(BIN)/$@ $^ $(LIBS) $(LDFLAGS)
-	./$(BIN)/$@ $(ARGS)
+digest: $(OBJS)
+	$(CC) $(CFLAGS) -o $(BIN)/digest $(addprefix $(BIN)/, $(notdir $^)) $(LIBS) $(LDFLAGS)
 
-# Convert the source in object, but before all, run `$(BIN)` aka mkdir
+# Convert the source in object
 $(BIN)/%.o: %.c
-	mkdir -p $(@D)
-	$(CC) $(CFLAGS) -o $@ -c $< $(LDFLAGS)
+	mkdir -p $(BIN)
+	$(CC) $(CFLAGS) -o $(BIN)/$(notdir $@) -c $< $(LDFLAGS)
 
 # Echo the source and object values
 help:
 	@echo "src: $(SRCS)"
 	@echo "obj: $(OBJS)"
-	@echo "obj_test: $(OBJ_TEST)"
 
 clean:
 	rm -rf $(BIN)
-	
-.PHONY: test-draw help clean main
diff --git a/digest/digest.c b/digest/digest.c
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3c19f31a09370c67cff8cd216943aa36e7f268b9 100644
--- a/digest/digest.c
+++ b/digest/digest.c
@@ -0,0 +1,99 @@
+#include "digest.h"
+
+#define BUF_MAXSIZE 4096
+
+//=========================
+// PRIVATE
+//=========================
+
+/**
+ * @brief Stringify the given bytes digest
+ *
+ * @param md_len
+ * @param md_value
+ * @return char*
+ */
+static char *stringify_digest(unsigned int md_len, unsigned char md_value[]) {
+    size_t hexlen = 2;
+    size_t outdigestlen = md_len * hexlen;
+
+    char *digest = malloc(outdigestlen + 1);
+    char *hex = digest;
+
+    for (size_t i = 0; i < md_len; i++) {
+        hex += sprintf(hex, "%02x", md_value[i]);
+    }
+
+    return digest;
+}
+
+/**
+ * @brief Initialize the EVP context
+ *
+ * @param digest_method
+ * @return EVP_MD_CTX*
+ */
+EVP_MD_CTX *EVP_context_init(char *digest_method) {
+    EVP_MD_CTX *mdctx;
+    const EVP_MD *md;
+
+    if (digest_method == NULL) {
+        fprintf(stderr, "Digest method not provided.\n");
+        exit(ENOMSG);
+    }
+
+    md = EVP_get_digestbyname(digest_method);
+    if (md == NULL) {
+        fprintf(stderr, "Digest method not found.\n");
+        exit(ENOPROTOOPT);
+    }
+
+    mdctx = EVP_MD_CTX_new();
+    EVP_DigestInit_ex2(mdctx, md, NULL);
+
+    return mdctx;
+}
+
+//=========================
+// PUBLIC
+//=========================
+
+char *str_digest(char *foo, char *digest_method) {
+    EVP_MD_CTX *mdctx = EVP_context_init(digest_method);
+    unsigned char md_value[EVP_MAX_MD_SIZE];
+    unsigned int md_len;
+
+    EVP_DigestUpdate(mdctx, foo, strlen(foo));
+    EVP_DigestFinal_ex(mdctx, md_value, &md_len);
+    EVP_MD_CTX_free(mdctx);
+
+    return stringify_digest(md_len, md_value);
+}
+
+char *file_digest(char *filename, char *digest_method) {
+    EVP_MD_CTX *mdctx = EVP_context_init(digest_method);
+    unsigned char md_value[EVP_MAX_MD_SIZE];
+    unsigned int md_len;
+
+    FILE *f;
+    char buf[BUF_MAXSIZE];
+
+    // case of STDIN
+    if (filename == NULL) {
+        f = stdin;
+    } else {
+        if ((f = fopen(filename, "r")) == NULL) {
+            perror(filename);
+            exit(ENOENT);
+        }
+    }
+
+    while (fgets(buf, BUF_MAXSIZE, f) != NULL) {
+        EVP_DigestUpdate(mdctx, buf, strlen(buf));
+    }
+
+    EVP_DigestFinal_ex(mdctx, md_value, &md_len);
+    EVP_MD_CTX_free(mdctx);
+
+    return stringify_digest(md_len, md_value);
+}
diff --git a/digest/digest.h b/digest/digest.h
index cb35c12962a75cf9f0fc76bdca3fab38fafef7c1..815f112425acb3e426bfeef90d6e719ee5dccf54 100644
--- a/digest/digest.h
+++ b/digest/digest.h
@@ -1,4 +1,26 @@
 #ifndef DIGEST_H
 #define DIGEST_H
 
+#include <errno.h>
+#include <openssl/evp.h>
+#include <string.h>
+
+/**
+ * @brief Make the digest of the given string
+ *
+ * @param foo
+ * @param digest_method
+ * @return char*
+ */
+char *str_digest(char *foo, char *digest_method);
+
+/**
+ * @brief Make the digest of the given file
+ *
+ * @param filename If null, read STDIN
+ * @param digest_method
+ * @return char*
+ */
+char *file_digest(char *filename, char *digest_method);
+
 #endif // DIGEST_H
diff --git a/main.c b/main.c
index b24433f7e9b44c1818127001a149d094cad3ee2d..e57b25b68e7fe2c2c932be3a4f01a56e9a6f3c6b 100644
--- a/main.c
+++ b/main.c
@@ -1,15 +1,79 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
 
 #include "digest/digest.h"
 #include "options/opt.h"
 
+/**
+ * @brief Join an array of string
+ * @see https://stackoverflow.com/a/4681415
+ *
+ * @param foo
+ * @param count
+ * @return char*
+ */
+char *join(char *foo[], int count) {
+    char *out = NULL;
+    size_t total_len = 0;
+
+    for (int i = 0; i < count; i++)
+        total_len += strlen(foo[i]);
+    total_len += count - 1; // seperator
+    total_len++;            // string terminator
+
+    out = malloc(total_len);
+    out[0] = '\0';
+
+    for (int i = 0; i < count; i++) {
+        strcat(out, foo[i]);
+        if (i < (count - 1))
+            strcat(out, " ");
+    }
+
+    return out;
+}
+
 int main(int argc, char *argv[]) {
-    for (int i = 1; i < argc; i++) {
-        printf("%s\n", argv[i]);
+    opt *opts = verify_options(argc, argv);
+    char *digest;
+
+    switch (opts->flag) {
+    case W_FLAG:
+        for (int i = 0; i < opts->extra_count; i++) {
+            digest = str_digest(opts->extra[i], opts->digest_method);
+
+            printf("%s\t%s\n", digest, opts->extra[i]);
+            free(digest);
+        }
+        break;
+
+    case F_FLAG:
+        for (int i = 0; i < opts->extra_count; i++) {
+            digest = file_digest(opts->extra[i], opts->digest_method);
+
+            printf("%s\t%s\n", digest, opts->extra[i]);
+            free(digest);
+        }
+        break;
+
+    case S_FLAG:
+        digest = file_digest(NULL, opts->digest_method);
+
+        printf("%s\n", digest);
+        free(digest);
+        break;
+
+    default:
+        char *foo = join(opts->extra, opts->extra_count);
+        digest = str_digest(foo, opts->digest_method);
+
+        printf("%s\t%s\n", digest, foo);
+        free(digest);
+        break;
     }
 
+    discard_options(opts);
+
     exit(EXIT_SUCCESS);
 }
diff --git a/options/opt.c b/options/opt.c
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1d96720c9318ad8ba548e531d45f38c6d01d7c59 100644
--- a/options/opt.c
+++ b/options/opt.c
@@ -0,0 +1,63 @@
+#include "opt.h"
+
+//=========================
+// PUBLIC
+//=========================
+
+opt *verify_options(int argc, char *argv[]) {
+    int option;
+    opt *verified = malloc(sizeof(opt));
+    verified->flag = 0;
+    verified->digest_method = NULL;
+
+    while ((option = getopt(argc, argv, "wfst:")) != -1) {
+        // Argument list too long
+        if (verified->flag != 0 && option != 't') {
+            printf("Cannot choose mulitple options.\n");
+            exit(E2BIG);
+        }
+
+        switch (option) {
+        case 'w':
+            verified->flag = 1 << 0;
+            break;
+
+        case 'f':
+            verified->flag = 1 << 1;
+            break;
+
+        case 's':
+            verified->flag = 1 << 2;
+            break;
+
+        case 't':
+            // optarg hold the value of the current option
+            verified->digest_method = optarg;
+            break;
+
+        // Invalid argument
+        default:
+            exit(EINVAL);
+            break;
+        }
+    }
+
+    if (verified->digest_method == NULL) {
+        verified->digest_method = "SHA1";
+    }
+
+    verified->extra_count = argc - optind;
+    verified->extra = malloc(sizeof(char *) * verified->extra_count);
+    // optind not found in vscode, but the variable simply store the index
+    // of the first non-argument term passed to the arguments list.
+    for (int i = optind; i < argc; i++) {
+        verified->extra[i - optind] = argv[i];
+    }
+
+    return verified;
+}
+
+void discard_options(opt *o) {
+    free(o->extra);
+    free(o);
+}
diff --git a/options/opt.h b/options/opt.h
index 7bc9bafbee7f41f4bce4b4b51c77e4c028dd816e..c858e387377f9a7674266b39928bc286c2b08c09 100644
--- a/options/opt.h
+++ b/options/opt.h
@@ -1,4 +1,42 @@
 #ifndef OPT_H
 #define OPT_H
 
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define W_FLAG 1 << 0
+#define F_FLAG 1 << 1
+#define S_FLAG 1 << 2
+
+typedef struct _opt {
+    char flag;
+    char **extra;
+    int extra_count;
+    char *digest_method; // default SHA1
+} opt;
+
+/**
+ * @brief Verify passed options, and returns the corresponding flag.
+ *
+ * -w : 0x1
+ * -f : 0x2
+ * -s : 0x4
+ *
+ * other : error
+ *
+ * @param argc
+ * @param argv
+ * @return opt
+ */
+opt *verify_options(int argc, char *argv[]);
+
+/**
+ * @brief Discard the given options
+ *
+ * @param o
+ */
+void discard_options(opt *o);
+
 #endif // OPT_H