···11+# secret-santa
22+Simple secret santa program in C, outputting a base64-encoded list of recievers that can be pasted to the corresponding givers.
33+44+Using libb64's impl of encoding.
55+66+## Usage
77+88+```bash
99+> gcc -o secret_santa main.c
1010+> echo "albert bobby colin" | ./secret_santa
1111+Seed: 12345
1212+colin: (base 64 encoding of the word bobby)
1313+albert: (base 64 encoding of the word colin)
1414+bobby: (base 64 encoding of the word albert)
1515+```
1616+1717+### Arguments
1818+`-s` seed, for replicability.
1919+`-d` decode/debug, leave the recipients as plaintext.
2020+
+245
main.c
···11+#include <stdio.h>
22+#include <stdlib.h>
33+#include <string.h>
44+#include <time.h>
55+#include <stdbool.h>
66+77+#define BUFFER_SIZE 4096
88+#define MAX_NAMES 128
99+1010+#define BASE64_CENCODE_H
1111+1212+typedef enum
1313+{
1414+ step_A, step_B, step_C
1515+} base64_encodestep;
1616+1717+typedef struct
1818+{
1919+ base64_encodestep step;
2020+ char result;
2121+ int stepcount;
2222+} base64_encodestate;
2323+2424+2525+/*
2626+cencoder.c - c source to a base64 encoding algorithm implementation
2727+2828+This is part of the libb64 project, and has been placed in the public domain.
2929+For details, see http://sourceforge.net/projects/libb64
3030+*/
3131+3232+3333+const int CHARS_PER_LINE = 72;
3434+3535+void base64_init_encodestate(base64_encodestate* state_in)
3636+{
3737+ state_in->step = step_A;
3838+ state_in->result = 0;
3939+ state_in->stepcount = 0;
4040+}
4141+4242+char base64_encode_value(char value_in)
4343+{
4444+ static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4545+ if (value_in > 63) return '=';
4646+ return encoding[(int)value_in];
4747+}
4848+4949+int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
5050+{
5151+ const char* plainchar = plaintext_in;
5252+ const char* const plaintextend = plaintext_in + length_in;
5353+ char* codechar = code_out;
5454+ char result;
5555+ char fragment;
5656+5757+ result = state_in->result;
5858+5959+ switch (state_in->step)
6060+ {
6161+ while (1)
6262+ {
6363+ case step_A:
6464+ if (plainchar == plaintextend)
6565+ {
6666+ state_in->result = result;
6767+ state_in->step = step_A;
6868+ return codechar - code_out;
6969+ }
7070+ fragment = *plainchar++;
7171+ result = (fragment & 0x0fc) >> 2;
7272+ *codechar++ = base64_encode_value(result);
7373+ result = (fragment & 0x003) << 4;
7474+ case step_B:
7575+ if (plainchar == plaintextend)
7676+ {
7777+ state_in->result = result;
7878+ state_in->step = step_B;
7979+ return codechar - code_out;
8080+ }
8181+ fragment = *plainchar++;
8282+ result |= (fragment & 0x0f0) >> 4;
8383+ *codechar++ = base64_encode_value(result);
8484+ result = (fragment & 0x00f) << 2;
8585+ case step_C:
8686+ if (plainchar == plaintextend)
8787+ {
8888+ state_in->result = result;
8989+ state_in->step = step_C;
9090+ return codechar - code_out;
9191+ }
9292+ fragment = *plainchar++;
9393+ result |= (fragment & 0x0c0) >> 6;
9494+ *codechar++ = base64_encode_value(result);
9595+ result = (fragment & 0x03f) >> 0;
9696+ *codechar++ = base64_encode_value(result);
9797+9898+ ++(state_in->stepcount);
9999+ if (state_in->stepcount == CHARS_PER_LINE/4)
100100+ {
101101+ *codechar++ = '\n';
102102+ state_in->stepcount = 0;
103103+ }
104104+ }
105105+ }
106106+ /* control should not reach here */
107107+ return codechar - code_out;
108108+}
109109+110110+int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
111111+{
112112+ char* codechar = code_out;
113113+114114+ switch (state_in->step)
115115+ {
116116+ case step_B:
117117+ *codechar++ = base64_encode_value(state_in->result);
118118+ *codechar++ = '=';
119119+ *codechar++ = '=';
120120+ break;
121121+ case step_C:
122122+ *codechar++ = base64_encode_value(state_in->result);
123123+ *codechar++ = '=';
124124+ break;
125125+ case step_A:
126126+ break;
127127+ }
128128+ *codechar++ = '\n';
129129+130130+ return codechar - code_out;
131131+}
132132+133133+char* encode(const char* input)
134134+{
135135+ /* set up a destination buffer large enough to hold the encoded data */
136136+ char* output = (char*)malloc(BUFFER_SIZE);
137137+ /* keep track of our encoded position */
138138+ char* c = output;
139139+ /* store the number of bytes encoded by a single call */
140140+ int cnt = 0;
141141+ /* we need an encoder state */
142142+ base64_encodestate s;
143143+144144+ /*---------- START ENCODING ----------*/
145145+ /* initialise the encoder state */
146146+ base64_init_encodestate(&s);
147147+ /* gather data from the input and send it to the output */
148148+ cnt = base64_encode_block(input, strlen(input), c, &s);
149149+ c += cnt;
150150+ /* since we have encoded the entire input string, we know that
151151+ there is no more input data; finalise the encoding */
152152+ cnt = base64_encode_blockend(c, &s);
153153+ c += cnt;
154154+ /*---------- STOP ENCODING ----------*/
155155+156156+ /* we want to print the encoded data, so null-terminate it: */
157157+ *c = 0;
158158+159159+ return output;
160160+}
161161+162162+void shuffle(int *array, int size, unsigned int seed) {
163163+ srand(seed);
164164+ for (int i = size - 1; i > 0; i--) {
165165+ int j = rand() % (i + 1);
166166+ int temp = array[i];
167167+ array[i] = array[j];
168168+ array[j] = temp;
169169+ }
170170+}
171171+172172+int main(int argc, char *argv[]) {
173173+ char buffer[BUFFER_SIZE];
174174+ char *names[MAX_NAMES];
175175+ int indices[MAX_NAMES];
176176+ int name_count = 0;
177177+ unsigned int seed;
178178+ bool seed_provided = false;
179179+ bool encode_partner = true;
180180+181181+ for (int i = 1; i < argc; i++) {
182182+ if (strcmp(argv[i], "-s") == 0 && i + 1 < argc) {
183183+ seed = (unsigned int)strtoul(argv[i + 1], NULL, 10);
184184+ seed_provided = true;
185185+ }
186186+ if (strcmp(argv[i], "-d") == 0) {
187187+ encode_partner = false;
188188+ }
189189+ }
190190+191191+ if (!seed_provided) {
192192+ seed = (unsigned int)time(NULL);
193193+ }
194194+195195+ printf("Seed: %u\n", seed);
196196+197197+ if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
198198+ perror("Error reading input");
199199+ return 1;
200200+ }
201201+202202+ size_t len = strlen(buffer);
203203+ if (len > 0 && buffer[len - 1] == '\n') {
204204+ buffer[len - 1] = '\0';
205205+ }
206206+207207+ char *token = strtok(buffer, " ");
208208+ while (token != NULL) {
209209+ if (name_count >= MAX_NAMES) {
210210+ fprintf(stderr, "Too many names (max %d)\n", MAX_NAMES);
211211+ return 1;
212212+ }
213213+ names[name_count] = strdup(token);
214214+ indices[name_count] = name_count;
215215+ name_count++;
216216+ token = strtok(NULL, " ");
217217+ }
218218+219219+ if (name_count < 2) {
220220+ fprintf(stderr, "Need at least two names for Secret Santa\n");
221221+ return 1;
222222+ }
223223+224224+ shuffle(indices, name_count, seed);
225225+226226+ int offset = seed;
227227+ if (offset % name_count == 0) {
228228+ offset = 1;
229229+ }
230230+ for (int i = 0; i < name_count; i++) {
231231+ int giver = indices[i];
232232+ int receiver = indices[(i + offset) % name_count];
233233+ if (encode_partner) {
234234+ printf("%s: %s\n", names[giver], encode(names[receiver]));
235235+ } else {
236236+ printf("%s: %s\n", names[giver], names[receiver]);
237237+ }
238238+ }
239239+240240+ for (int i = 0; i < name_count; i++) {
241241+ free(names[i]);
242242+ }
243243+244244+ return 0;
245245+}