This repository has no description
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <time.h>
5#include <stdbool.h>
6
7#define BUFFER_SIZE 4096
8#define MAX_NAMES 128
9
10#define BASE64_CENCODE_H
11
12typedef enum
13{
14 step_A, step_B, step_C
15} base64_encodestep;
16
17typedef struct
18{
19 base64_encodestep step;
20 char result;
21 int stepcount;
22} base64_encodestate;
23
24
25/*
26cencoder.c - c source to a base64 encoding algorithm implementation
27
28This is part of the libb64 project, and has been placed in the public domain.
29For details, see http://sourceforge.net/projects/libb64
30*/
31
32
33const int CHARS_PER_LINE = 72;
34
35void base64_init_encodestate(base64_encodestate* state_in)
36{
37 state_in->step = step_A;
38 state_in->result = 0;
39 state_in->stepcount = 0;
40}
41
42char base64_encode_value(char value_in)
43{
44 static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
45 if (value_in > 63) return '=';
46 return encoding[(int)value_in];
47}
48
49int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
50{
51 const char* plainchar = plaintext_in;
52 const char* const plaintextend = plaintext_in + length_in;
53 char* codechar = code_out;
54 char result;
55 char fragment;
56
57 result = state_in->result;
58
59 switch (state_in->step)
60 {
61 while (1)
62 {
63 case step_A:
64 if (plainchar == plaintextend)
65 {
66 state_in->result = result;
67 state_in->step = step_A;
68 return codechar - code_out;
69 }
70 fragment = *plainchar++;
71 result = (fragment & 0x0fc) >> 2;
72 *codechar++ = base64_encode_value(result);
73 result = (fragment & 0x003) << 4;
74 case step_B:
75 if (plainchar == plaintextend)
76 {
77 state_in->result = result;
78 state_in->step = step_B;
79 return codechar - code_out;
80 }
81 fragment = *plainchar++;
82 result |= (fragment & 0x0f0) >> 4;
83 *codechar++ = base64_encode_value(result);
84 result = (fragment & 0x00f) << 2;
85 case step_C:
86 if (plainchar == plaintextend)
87 {
88 state_in->result = result;
89 state_in->step = step_C;
90 return codechar - code_out;
91 }
92 fragment = *plainchar++;
93 result |= (fragment & 0x0c0) >> 6;
94 *codechar++ = base64_encode_value(result);
95 result = (fragment & 0x03f) >> 0;
96 *codechar++ = base64_encode_value(result);
97
98 ++(state_in->stepcount);
99 if (state_in->stepcount == CHARS_PER_LINE/4)
100 {
101 *codechar++ = '\n';
102 state_in->stepcount = 0;
103 }
104 }
105 }
106 /* control should not reach here */
107 return codechar - code_out;
108}
109
110int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
111{
112 char* codechar = code_out;
113
114 switch (state_in->step)
115 {
116 case step_B:
117 *codechar++ = base64_encode_value(state_in->result);
118 *codechar++ = '=';
119 *codechar++ = '=';
120 break;
121 case step_C:
122 *codechar++ = base64_encode_value(state_in->result);
123 *codechar++ = '=';
124 break;
125 case step_A:
126 break;
127 }
128 *codechar++ = '\n';
129
130 return codechar - code_out;
131}
132
133char* encode(const char* input)
134{
135 /* set up a destination buffer large enough to hold the encoded data */
136 char* output = (char*)malloc(BUFFER_SIZE);
137 /* keep track of our encoded position */
138 char* c = output;
139 /* store the number of bytes encoded by a single call */
140 int cnt = 0;
141 /* we need an encoder state */
142 base64_encodestate s;
143
144 /*---------- START ENCODING ----------*/
145 /* initialise the encoder state */
146 base64_init_encodestate(&s);
147 /* gather data from the input and send it to the output */
148 cnt = base64_encode_block(input, strlen(input), c, &s);
149 c += cnt;
150 /* since we have encoded the entire input string, we know that
151 there is no more input data; finalise the encoding */
152 cnt = base64_encode_blockend(c, &s);
153 c += cnt;
154 /*---------- STOP ENCODING ----------*/
155
156 /* we want to print the encoded data, so null-terminate it: */
157 *c = 0;
158
159 return output;
160}
161
162void shuffle(int *array, int size, unsigned int seed) {
163 srand(seed);
164 for (int i = size - 1; i > 0; i--) {
165 int j = rand() % (i + 1);
166 int temp = array[i];
167 array[i] = array[j];
168 array[j] = temp;
169 }
170}
171
172int main(int argc, char *argv[]) {
173 char buffer[BUFFER_SIZE];
174 char *names[MAX_NAMES];
175 int indices[MAX_NAMES];
176 int name_count = 0;
177 unsigned int seed;
178 bool seed_provided = false;
179 bool encode_partner = true;
180
181 for (int i = 1; i < argc; i++) {
182 if (strcmp(argv[i], "-s") == 0 && i + 1 < argc) {
183 seed = (unsigned int)strtoul(argv[i + 1], NULL, 10);
184 seed_provided = true;
185 }
186 if (strcmp(argv[i], "-d") == 0) {
187 encode_partner = false;
188 }
189 }
190
191 if (!seed_provided) {
192 seed = (unsigned int)time(NULL);
193 }
194
195 printf("Seed: %u\n", seed);
196
197 if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
198 perror("Error reading input");
199 return 1;
200 }
201
202 size_t len = strlen(buffer);
203 if (len > 0 && buffer[len - 1] == '\n') {
204 buffer[len - 1] = '\0';
205 }
206
207 char *token = strtok(buffer, " ");
208 while (token != NULL) {
209 if (name_count >= MAX_NAMES) {
210 fprintf(stderr, "Too many names (max %d)\n", MAX_NAMES);
211 return 1;
212 }
213 names[name_count] = strdup(token);
214 indices[name_count] = name_count;
215 name_count++;
216 token = strtok(NULL, " ");
217 }
218
219 if (name_count < 2) {
220 fprintf(stderr, "Need at least two names for Secret Santa\n");
221 return 1;
222 }
223
224 shuffle(indices, name_count, seed);
225
226 int offset = seed;
227 if (offset % name_count == 0) {
228 offset = 1;
229 }
230 for (int i = 0; i < name_count; i++) {
231 int giver = indices[i];
232 int receiver = indices[(i + offset) % name_count];
233 if (encode_partner) {
234 printf("%s: %s\n", names[giver], encode(names[receiver]));
235 } else {
236 printf("%s: %s\n", names[giver], names[receiver]);
237 }
238 }
239
240 for (int i = 0; i < name_count; i++) {
241 free(names[i]);
242 }
243
244 return 0;
245}