summaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
authorGentoo <installgentoo@endianness.com>2021-03-27 10:20:15 +1100
committerGentoo <installgentoo@endianness.com>2021-03-27 10:20:15 +1100
commitcc068dd1b885c884659e4d36e7d4aa81c52dc89c (patch)
tree73ebdfe6bade1b58fb0cec014e762d84e38b7a9a /main.c
downloadbase64-cc068dd1b885c884659e4d36e7d4aa81c52dc89c.tar.gz
base64-cc068dd1b885c884659e4d36e7d4aa81c52dc89c.tar.bz2
base64-cc068dd1b885c884659e4d36e7d4aa81c52dc89c.zip
initial commit
Diffstat (limited to 'main.c')
-rw-r--r--main.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..5a51fbc
--- /dev/null
+++ b/main.c
@@ -0,0 +1,155 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h> //just for ENOENT
+#include <sys/stat.h> //just to check for folder
+#include "main.h"
+
+int main(int argc, char *argv[])
+{
+bool decode = false; //decoding is set to false by default (default is to encode)
+
+//malloc the buffer to store the input string in
+unsigned char *buffer = malloc(DEFAULT_SIZE*sizeof(unsigned char));
+if (!buffer){fprintf(stderr,"Malloc Failed!\n"); exit(1);}
+int size = DEFAULT_SIZE-1;//-1 to account for the added NULL char
+
+//wrap encoded lines after COLS character (default 76).
+int wrap = WRAP_CHAR;
+
+//Go into stdin mode if there are no cli args
+if (argc == 1){stdinMode(buffer, wrap, decode, argv[0]);}//stdinmode is given a pointer to the input string and addittionally the amount of chars to wrap whether default or user set
+
+//arguments processing
+int argvPos = 1;
+
+while ((argv[argvPos]) && (argv[argvPos][0] == '-'))
+{
+if (argv[argvPos][1] == '-')
+ {
+ if ((memcmp(argv[argvPos],"--wrap=",7)) == 0)
+ {
+ wrap = atoi(argv[argvPos]+7);//overwrite the default wrap size with the new supplied one
+ if (wrap < 0){printf("%s: invalid wrap size: \'%s\'\n", argv[0], argv[argvPos]+7); exit(1);}//if atoi() returns negative, the input wasn't a positive int
+ goto nextArgument;
+ }
+
+ if ((memcmp(argv[argvPos],"--decode",8)) == 0)
+ {
+ decode = true;
+ goto nextArgument;
+ }
+
+ if ((memcmp(argv[argvPos],"--help",6)) == 0)
+ {
+ printf("Usage %s [OPTION]... [FILE]\n", argv[0]);
+ printf("Base64 encode FILE, or standard input, to standard output.\n");
+ printf("With no FILE, or when FILE is -, read standard input\n\n");
+ printf("Mandatory arguments to long options are mandatory for short options too.\n");
+ printf(" -d, --decode\t\tdecode data.\n");
+ printf(" -w, --wrap=COLS\twrap encoded lines after COLS character (default 76).\n");
+ printf("\t\t\t Use 0 to disable line wrapping\n\n");
+ printf("This program is part of UNG.\n");
+ printf("Version: 0.1\n");
+ exit(0);
+ }
+ printf("%s: unrecognized option -- \'%s\'\n", argv[0], argv[argvPos]);//if here is reached, the option wasn't valid
+ exit(1);
+ }
+
+if ((memcmp(argv[argvPos],"-w",2)) == 0)
+ {
+ if (!argv[argvPos+1]){printf("%s: option requires an argument -- \'%c\'\n",argv[0],argv[argvPos][1]); exit(1);}//this triggers if -w hasn't been given a value
+ wrap = atoi(argv[++argvPos]);//overwrite the default wrap size with the new supplied one
+ if (!wrap){printf("%s: invalid wrap size: \'%s\'\n", argv[0], argv[argvPos]); exit(1);}
+ goto nextArgument;
+ }
+
+if ((memcmp(argv[argvPos],"-d",2)) == 0)
+ {
+ decode = true;
+ goto nextArgument;
+ }
+
+if (!argv[argvPos][1]){stdinMode(buffer, wrap, decode, argv[0]);}//if a '-' was detected, but the next char is NULL, '-' was inputted as a file, so stdinMode is activated
+printf("%s: invalid option -- \'%c\'\n", argv[0], argv[argvPos][1]);//if here is reached, the option wasn't valid
+exit(1);
+
+nextArgument: ++argvPos;//get read to process the next argument
+}
+
+if (!argv[argvPos]){stdinMode(buffer, wrap, decode, argv[0]);}//if no more operands were provided after options, go into stdin mode
+if (argv[argvPos+1]){printf("%s: extra operand \'%s\'\n", argv[0], argv[argvPos]); exit(1);}//if there are TWO and not ONE addittional argv arg's at this point, the operaterand to the left of the "FILE" is extra
+
+
+//file processing mode
+int result;
+int i = 0; //keeps track of buffer to write
+FILE *fp;
+struct stat sb;//struct used by stat()
+
+if (stat(argv[argvPos], &sb) == 0 && S_ISDIR(sb.st_mode)){fprintf(stderr, "%s: read error: Is a directory\n", argv[0]); free(buffer); exit(1);}//check if cli argv is a folder
+
+fp = fopen(argv[argvPos],"rb");//rb for reading binary
+if (!fp)//if file failed to open
+ {
+ if (errno == ENOENT){fprintf(stderr,"%s: %s: No such file or directory\n", argv[0], argv[argvPos]); free(buffer); exit(1);}//ENOENT is returned if there is no such file or directory
+ fprintf(stderr, "%s: %s: Could not open\n", argv[0], argv[argvPos]); free(buffer); exit(1);//all other errors are blanket handled
+ }
+
+result = fread(buffer+i, 1, sizeof(unsigned char)*DEFAULT_SIZE-1, fp);//attempt to read up to DEFAULT_SIZE from file. (-1 to account for NULL char to be added)
+if (!result){fclose(fp); free(buffer); exit(1);}//fread will fail if file is empty, so just exit.
+i+=result;//add result to i so chars in buffer aren't overwritten next fread()
+
+readAgain: if (result == (sizeof(unsigned char)*DEFAULT_SIZE-1))//if the file is longer than DEFAULT_SIZE, result will be the size of DEFAULT_SIZE
+ {
+ size += DEFAULT_SIZE;//increase size of buffer by DEFAULT_SIZE each time
+ buffer = realloc(buffer,size*sizeof(unsigned char));
+ if (!buffer){fprintf(stderr,"Realloc Failed!\n"); exit(1);}
+
+ result = fread(buffer+i, 1, sizeof(unsigned char)*DEFAULT_SIZE-1, fp);//attempt to read up to DEFAULT_SIZE from file
+ if (!result){goto perfectSize;}//the previous fread() was the perfect size, so jump to processing
+ i+=result;//add result to i so chars in buffer aren't overwritten next fread()
+ goto readAgain;//repeat until result is less than DEFAULT_SIZE
+ }
+
+perfectSize: buffer[i] = '\0';//add null char since function expects it
+
+if (!decode)
+ {
+ char *output = base64Encode(buffer, i);
+ if (!output){fprintf(stderr, "Malloc Failed!\n"); exit(1);}
+ if (wrap == 0){result = fwrite(output, 1, sizeof(unsigned char)*strlen(output), stdout); goto exit;}//if wrap is set to 0, do no wrapping.
+
+ int charactersLeft = strlen(output);//the total number of characters to print is strlen(output_
+ int x = 0;//position to print from in string so wrap printing works
+
+ while (charactersLeft > wrap)//keep looping until all of the wrap length writes are done
+ {
+ result = fwrite(output+x, 1, sizeof(unsigned char)*wrap, stdout);//write wrap number of characters at a time
+ if (!result){fprintf(stderr, "Fwrite Failed!\n"); exit(1);}//fwrite to stdout should not fail. It's best to just exit if it does.
+ putchar('\n');//add a newline to finish off the wrapped line
+ x += wrap;//increase the printing position to the next position
+ charactersLeft -= wrap;//decrease charactersLeft by how many were printed
+ }
+
+ if (charactersLeft == 0){goto exit;}//if the printed number of characters was perfect, don't print an extra newline
+
+ result = fwrite(output+x, 1, sizeof(unsigned char)*charactersLeft, stdout);//print any remaining characters that are smaller in number than wrap.
+ if (!result){fprintf(stderr, "Fwrite Failed!\n"); exit(1);}//fwrite to stdout should not fail. It's best to just exit if it does.
+ putchar('\n');//add a newline to finish off the wrapped line
+ goto exit;
+ }
+
+if (decode)
+ {
+ int outputLength = base64Decode(buffer, i);
+ if (!outputLength){fprintf(stderr,"%s: invalid input\n", argv[0]); free(buffer); exit(1);}//base64 returns -1 if input string was invalid
+ result = fwrite(buffer, 1, sizeof(unsigned char)*outputLength, stdout);
+ goto exit;
+ }
+
+exit: fclose(fp);//close the file
+free(buffer);
+return 0;
+}