wc: Added wc
[mutos-utils.git] / base64.c
blob28e733d0d395edfdd856262568a4f56ab7b02b63
1 /*
2 Copyright © 2013 Alastair Stuart
4 This program is open source software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
15 #include <ctype.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdint.h>
20 #include <stdbool.h>
21 #include <string.h>
23 #include <getopt.h>
25 #define VERSION "0.01"
27 const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
28 const int padding_table[] = {0, 2, 1};
30 void base64_encode_block(uint8_t in[3], char out[5])
32 uint8_t octet_a = in[0];
33 uint8_t octet_b = in[1];
34 uint8_t octet_c = in[2];
36 uint32_t combined = (octet_a << 16) + (octet_b << 8) + octet_c;
38 out[0] = base64_table[(combined >> 3 * 6) & 0x3F];
39 out[1] = base64_table[(combined >> 2 * 6) & 0x3F];
40 out[2] = base64_table[(combined >> 1 * 6) & 0x3F];
41 out[3] = base64_table[(combined >> 0 * 6) & 0x3F];
42 out[4] = '\0';
45 void usage(char* program)
47 printf("Usage: %s [options] [file]\n", program);
48 printf("Encodes a file into base64..\n"
49 "\n"
50 " -w, --wrap [num] Wrap lines after [num] characters.\n"
51 "\n"
52 " --help Print this message.\n"
53 " --version Show version info.\n");
56 int main(int argc, char* argv[])
58 size_t line_width = 0;
59 size_t wrap = 76;
60 static struct option long_options[] = {
61 {"wrap", required_argument, NULL, 'w'},
62 {"help", no_argument, NULL, 1},
63 {"version", no_argument, NULL, 2},
64 {NULL, 0, NULL, 0}
67 int c = 0;
68 while ((c = getopt_long(argc, argv, "w:",
69 long_options, NULL)) != -1)
71 switch (c)
73 case 'w':
74 // check if wrap argument is a valid number
75 for (size_t i = 0; i < strlen(optarg); i++)
77 if (!isdigit(optarg[i])) {
78 fprintf(stderr, "%s: invalid wrap size: %s\n",
79 argv[0], optarg);
80 return 1;
83 wrap = atoi(optarg);
84 break;
85 case 1:
86 usage(argv[0]);
87 return 0;
88 case 2:
89 printf("base64 (mutos) v"VERSION"\n");
90 return 0;
91 default:
92 printf("Run '%s --help' for usage.\n",
93 argv[0]);
94 return 1;
98 FILE* input = NULL;
99 char* filename = NULL;
101 if ((argc - optind) > 1) {
102 fprintf(stderr, "%s: extra operand: %s\n",
103 argv[0], argv[optind+1]);
104 return 1;
105 } else if ((argc - optind) < 1) {
106 input = stdin;
107 filename = "stdin";
108 } else {
109 input = fopen(argv[optind], "rb");
110 filename = argv[optind];
113 if (!input) {
114 fprintf(stderr, "%s: %s: %s\n",
115 argv[0], strerror(errno), filename);
116 return 1;
119 bool last_block = false;
121 size_t length = 0;
122 while (!last_block)
124 int eof_count = 0;
126 int c = 0;
128 uint8_t block[3] = {0};
129 block[0] = (c = fgetc(input)) != EOF ? c : 0;
130 if (c != EOF) { length++; } else { eof_count++; }
131 block[1] = (c = fgetc(input)) != EOF ? c : 0;
132 if (c != EOF) { length++; } else { eof_count++; }
133 block[2] = (c = fgetc(input)) != EOF ? c : 0;
134 if (c != EOF) { length++; } else { eof_count++; }
136 if (feof(input)) {
137 last_block = true;
140 if (eof_count == 3) {
141 break;
144 char encoded[5] = {'\0'};
145 base64_encode_block(block, encoded);
147 if (last_block) {
148 for (int i = 0; i < padding_table[length % 3]; i++)
150 encoded[3-i] = '=';
154 for (size_t i = 0; i < 4; i++)
156 printf("%c", encoded[i]);
157 line_width++;
158 if (wrap != 0) {
159 if (line_width % wrap == 0) {
160 printf("\n");
161 line_width = 0;
166 printf("\n");
168 fclose(input);
170 return 0;