aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2023-04-10 00:31:37 +0100
committerGitHub <noreply@github.com>2023-04-10 00:31:37 +0100
commitf3ba877fc52ff902b211e58d3c0e6e005bf3ab84 (patch)
treedb37c7caaf1c40ebf8b2b3527a7598b6d1fe39b5
parent2699911c7bf1f409e74fd45888441d990e5f81da (diff)
parentc5c9938bcabccd143a967d74a9fc135beeee8002 (diff)
downloadperlweeklychallenge-club-f3ba877fc52ff902b211e58d3c0e6e005bf3ab84.tar.gz
perlweeklychallenge-club-f3ba877fc52ff902b211e58d3c0e6e005bf3ab84.tar.bz2
perlweeklychallenge-club-f3ba877fc52ff902b211e58d3c0e6e005bf3ab84.zip
Merge pull request #7873 from pauloscustodio/master
Add solution
-rw-r--r--challenge-001/paulo-custodio/brainfuck.py2
-rw-r--r--challenge-001/paulo-custodio/c/ch-1.c28
-rw-r--r--challenge-001/paulo-custodio/c/utstring.h407
-rw-r--r--challenge-001/paulo-custodio/test.pl2
-rw-r--r--challenge-022/paulo-custodio/c/ch-1.c54
-rw-r--r--challenge-022/paulo-custodio/c/ch-2.c233
-rw-r--r--challenge-022/paulo-custodio/c/utarray.h252
-rw-r--r--challenge-022/paulo-custodio/c/uthash.h1140
-rw-r--r--challenge-022/paulo-custodio/c/utstring.h407
9 files changed, 2505 insertions, 20 deletions
diff --git a/challenge-001/paulo-custodio/brainfuck.py b/challenge-001/paulo-custodio/brainfuck.py
index 9d68e92acc..7316bd6456 100644
--- a/challenge-001/paulo-custodio/brainfuck.py
+++ b/challenge-001/paulo-custodio/brainfuck.py
@@ -131,6 +131,6 @@ if len(args)!=1:
with open(args[0]) as f:
prog = "".join(f.readlines())
-# initialize and run Tuting Machine
+# initialize and run Turing Machine
tm = TuringMachine(prog)
tm.run()
diff --git a/challenge-001/paulo-custodio/c/ch-1.c b/challenge-001/paulo-custodio/c/ch-1.c
index 54c2e8e58e..ea730a938b 100644
--- a/challenge-001/paulo-custodio/c/ch-1.c
+++ b/challenge-001/paulo-custodio/c/ch-1.c
@@ -11,13 +11,7 @@ is found in the string.
#include <string.h>
#include <stdlib.h>
#include <memory.h>
-
-void* check_mem(void* p) {
- if (!p) {
- fputs("out of memory", stderr);
- exit(EXIT_FAILURE);
- }
-}
+#include "utstring.h"
int replace_e(char* text) {
int count = 0;
@@ -31,16 +25,14 @@ int replace_e(char* text) {
}
int main(int argc, char* argv[]) {
- char* text = check_mem(strdup(""));
- for (int i = 1; i < argc; i++) {
- text = check_mem(realloc(text, strlen(text)+strlen(argv[i])+2));
- strcat(text, argv[i]);
- strcat(text, " ");
- }
- if (*text)
- text[strlen(text)-1] = '\0'; // remove last space
+ UT_string* text;
+ utstring_new(text);
+
+ for (int i = 1; i < argc; i++)
+ utstring_printf(text, "%s%s", i==1 ? "" : " ", argv[i]);
+
+ int count = replace_e(utstring_body(text));
+ printf("%d %s\n", count, utstring_body(text));
- int count = replace_e(text);
- printf("%d %s\n", count, text);
- free(text);
+ utstring_free(text);
}
diff --git a/challenge-001/paulo-custodio/c/utstring.h b/challenge-001/paulo-custodio/c/utstring.h
new file mode 100644
index 0000000000..f0270fb632
--- /dev/null
+++ b/challenge-001/paulo-custodio/c/utstring.h
@@ -0,0 +1,407 @@
+/*
+Copyright (c) 2008-2022, Troy D. Hanson https://troydhanson.github.io/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* a dynamic string implementation using macros
+ */
+#ifndef UTSTRING_H
+#define UTSTRING_H
+
+#define UTSTRING_VERSION 2.3.0
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifdef __GNUC__
+#define UTSTRING_UNUSED __attribute__((__unused__))
+#else
+#define UTSTRING_UNUSED
+#endif
+
+#ifdef oom
+#error "The name of macro 'oom' has been changed to 'utstring_oom'. Please update your code."
+#define utstring_oom() oom()
+#endif
+
+#ifndef utstring_oom
+#define utstring_oom() exit(-1)
+#endif
+
+typedef struct {
+ char *d; /* pointer to allocated buffer */
+ size_t n; /* allocated capacity */
+ size_t i; /* index of first unused byte */
+} UT_string;
+
+#define utstring_reserve(s,amt) \
+do { \
+ if (((s)->n - (s)->i) < (size_t)(amt)) { \
+ char *utstring_tmp = (char*)realloc( \
+ (s)->d, (s)->n + (amt)); \
+ if (!utstring_tmp) { \
+ utstring_oom(); \
+ } \
+ (s)->d = utstring_tmp; \
+ (s)->n += (amt); \
+ } \
+} while(0)
+
+#define utstring_init(s) \
+do { \
+ (s)->n = 0; (s)->i = 0; (s)->d = NULL; \
+ utstring_reserve(s,100); \
+ (s)->d[0] = '\0'; \
+} while(0)
+
+#define utstring_done(s) \
+do { \
+ if ((s)->d != NULL) free((s)->d); \
+ (s)->n = 0; \
+} while(0)
+
+#define utstring_free(s) \
+do { \
+ utstring_done(s); \
+ free(s); \
+} while(0)
+
+#define utstring_new(s) \
+do { \
+ (s) = (UT_string*)malloc(sizeof(UT_string)); \
+ if (!(s)) { \
+ utstring_oom(); \
+ } \
+ utstring_init(s); \
+} while(0)
+
+#define utstring_renew(s) \
+do { \
+ if (s) { \
+ utstring_clear(s); \
+ } else { \
+ utstring_new(s); \
+ } \
+} while(0)
+
+#define utstring_clear(s) \
+do { \
+ (s)->i = 0; \
+ (s)->d[0] = '\0'; \
+} while(0)
+
+#define utstring_bincpy(s,b,l) \
+do { \
+ utstring_reserve((s),(l)+1); \
+ if (l) memcpy(&(s)->d[(s)->i], b, l); \
+ (s)->i += (l); \
+ (s)->d[(s)->i]='\0'; \
+} while(0)
+
+#define utstring_concat(dst,src) \
+do { \
+ utstring_reserve((dst),((src)->i)+1); \
+ if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \
+ (dst)->i += (src)->i; \
+ (dst)->d[(dst)->i]='\0'; \
+} while(0)
+
+#define utstring_len(s) ((s)->i)
+
+#define utstring_body(s) ((s)->d)
+
+UTSTRING_UNUSED static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) {
+ int n;
+ va_list cp;
+ for (;;) {
+#ifdef _WIN32
+ cp = ap;
+#else
+ va_copy(cp, ap);
+#endif
+ n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp);
+ va_end(cp);
+
+ if ((n > -1) && ((size_t) n < (s->n-s->i))) {
+ s->i += n;
+ return;
+ }
+
+ /* Else try again with more space. */
+ if (n > -1) utstring_reserve(s,n+1); /* exact */
+ else utstring_reserve(s,(s->n)*2); /* 2x */
+ }
+}
+#ifdef __GNUC__
+/* support printf format checking (2=the format string, 3=start of varargs) */
+static void utstring_printf(UT_string *s, const char *fmt, ...)
+ __attribute__ (( format( printf, 2, 3) ));
+#endif
+UTSTRING_UNUSED static void utstring_printf(UT_string *s, const char *fmt, ...) {
+ va_list ap;
+ va_start(ap,fmt);
+ utstring_printf_va(s,fmt,ap);
+ va_end(ap);
+}
+
+/*******************************************************************************
+ * begin substring search functions *
+ ******************************************************************************/
+/* Build KMP table from left to right. */
+UTSTRING_UNUSED static void _utstring_BuildTable(
+ const char *P_Needle,
+ size_t P_NeedleLen,
+ long *P_KMP_Table)
+{
+ long i, j;
+
+ i = 0;
+ j = i - 1;
+ P_KMP_Table[i] = j;
+ while (i < (long) P_NeedleLen)
+ {
+ while ( (j > -1) && (P_Needle[i] != P_Needle[j]) )
+ {
+ j = P_KMP_Table[j];
+ }
+ i++;
+ j++;
+ if (i < (long) P_NeedleLen)
+ {
+ if (P_Needle[i] == P_Needle[j])
+ {
+ P_KMP_Table[i] = P_KMP_Table[j];
+ }
+ else
+ {
+ P_KMP_Table[i] = j;
+ }
+ }
+ else
+ {
+ P_KMP_Table[i] = j;
+ }
+ }
+
+ return;
+}
+
+
+/* Build KMP table from right to left. */
+UTSTRING_UNUSED static void _utstring_BuildTableR(
+ const char *P_Needle,
+ size_t P_NeedleLen,
+ long *P_KMP_Table)
+{
+ long i, j;
+
+ i = P_NeedleLen - 1;
+ j = i + 1;
+ P_KMP_Table[i + 1] = j;
+ while (i >= 0)
+ {
+ while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) )
+ {
+ j = P_KMP_Table[j + 1];
+ }
+ i--;
+ j--;
+ if (i >= 0)
+ {
+ if (P_Needle[i] == P_Needle[j])
+ {
+ P_KMP_Table[i + 1] = P_KMP_Table[j + 1];
+ }
+ else
+ {
+ P_KMP_Table[i + 1] = j;
+ }
+ }
+ else
+ {
+ P_KMP_Table[i + 1] = j;
+ }
+ }
+
+ return;
+}
+
+
+/* Search data from left to right. ( Multiple search mode. ) */
+UTSTRING_UNUSED static long _utstring_find(
+ const char *P_Haystack,
+ size_t P_HaystackLen,
+ const char *P_Needle,
+ size_t P_NeedleLen,
+ long *P_KMP_Table)
+{
+ long i, j;
+ long V_FindPosition = -1;
+
+ /* Search from left to right. */
+ i = j = 0;
+ while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) )
+ {
+ while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) )
+ {
+ i = P_KMP_Table[i];
+ }
+ i++;
+ j++;
+ if (i >= (int)P_NeedleLen)
+ {
+ /* Found. */
+ V_FindPosition = j - i;
+ break;
+ }
+ }
+
+ return V_FindPosition;
+}
+
+
+/* Search data from right to left. ( Multiple search mode. ) */
+UTSTRING_UNUSED static long _utstring_findR(
+ const char *P_Haystack,
+ size_t P_HaystackLen,
+ const char *P_Needle,
+ size_t P_NeedleLen,
+ long *P_KMP_Table)
+{
+ long i, j;
+ long V_FindPosition = -1;
+
+ /* Search from right to left. */
+ j = (P_HaystackLen - 1);
+ i = (P_NeedleLen - 1);
+ while ( (j >= 0) && (j >= i) )
+ {
+ while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) )
+ {
+ i = P_KMP_Table[i + 1];
+ }
+ i--;
+ j--;
+ if (i < 0)
+ {
+ /* Found. */
+ V_FindPosition = j + 1;
+ break;
+ }
+ }
+
+ return V_FindPosition;
+}
+
+
+/* Search data from left to right. ( One time search mode. ) */
+UTSTRING_UNUSED static long utstring_find(
+ UT_string *s,
+ long P_StartPosition, /* Start from 0. -1 means last position. */
+ const char *P_Needle,
+ size_t P_NeedleLen)
+{
+ long V_StartPosition;
+ long V_HaystackLen;
+ long *V_KMP_Table;
+ long V_FindPosition = -1;
+
+ if (P_StartPosition < 0)
+ {
+ V_StartPosition = s->i + P_StartPosition;
+ }
+ else
+ {
+ V_StartPosition = P_StartPosition;
+ }
+ V_HaystackLen = s->i - V_StartPosition;
+ if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) )
+ {
+ V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1));
+ if (V_KMP_Table != NULL)
+ {
+ _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table);
+
+ V_FindPosition = _utstring_find(s->d + V_StartPosition,
+ V_HaystackLen,
+ P_Needle,
+ P_NeedleLen,
+ V_KMP_Table);
+ if (V_FindPosition >= 0)
+ {
+ V_FindPosition += V_StartPosition;
+ }
+
+ free(V_KMP_Table);
+ }
+ }
+
+ return V_FindPosition;
+}
+
+
+/* Search data from right to left. ( One time search mode. ) */
+UTSTRING_UNUSED static long utstring_findR(
+ UT_string *s,
+ long P_StartPosition, /* Start from 0. -1 means last position. */
+ const char *P_Needle,
+ size_t P_NeedleLen)
+{
+ long V_StartPosition;
+ long V_HaystackLen;
+ long *V_KMP_Table;
+ long V_FindPosition = -1;
+
+ if (P_StartPosition < 0)
+ {
+ V_StartPosition = s->i + P_StartPosition;
+ }
+ else
+ {
+ V_StartPosition = P_StartPosition;
+ }
+ V_HaystackLen = V_StartPosition + 1;
+ if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) )
+ {
+ V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1));
+ if (V_KMP_Table != NULL)
+ {
+ _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table);
+
+ V_FindPosition = _utstring_findR(s->d,
+ V_HaystackLen,
+ P_Needle,
+ P_NeedleLen,
+ V_KMP_Table);
+
+ free(V_KMP_Table);
+ }
+ }
+
+ return V_FindPosition;
+}
+/*******************************************************************************
+ * end substring search functions *
+ ******************************************************************************/
+
+#endif /* UTSTRING_H */
diff --git a/challenge-001/paulo-custodio/test.pl b/challenge-001/paulo-custodio/test.pl
index 118c4fee8b..e05049e9fd 100644
--- a/challenge-001/paulo-custodio/test.pl
+++ b/challenge-001/paulo-custodio/test.pl
@@ -145,7 +145,7 @@ sub build {
}
if (/^brainfuck$/) {
#run("perl bfpp.pl <$prog_wo_ext.bfpp >$prog_wo_ext.bf");
- return "bf $prog_wo_ext.bf";
+ return "python3 ../../challenge-001/paulo-custodio/brainfuck.py $prog_wo_ext.bf";
}
if (/^c$/) {
run("gcc $prog -o $prog_wo_ext -lm -lmpfr -lgmp") if (!-f $exe || -M $exe > -M $prog);
diff --git a/challenge-022/paulo-custodio/c/ch-1.c b/challenge-022/paulo-custodio/c/ch-1.c
new file mode 100644
index 0000000000..52c30201ba
--- /dev/null
+++ b/challenge-022/paulo-custodio/c/ch-1.c
@@ -0,0 +1,54 @@
+/*
+Challenge 022
+
+Task #1
+Write a script to print first 10 Sexy Prime Pairs. Sexy primes are prime
+numbers that differ from each other by 6. For example, the numbers 5 and 11
+are both sexy primes, because 11 - 5 = 6. The term "sexy prime" is a pun
+stemming from the Latin word for six: sex. For more information, please
+checkout wiki page.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+bool is_prime(int n) {
+ if (n <= 1)
+ return false;
+ if (n <= 3)
+ return true;
+ if ((n % 2) == 0 || (n % 3) == 0)
+ return false;
+ for (int i = 5; i * i <= n; i += 6)
+ if ((n % i) == 0 || (n % (i + 2)) == 0)
+ return false;
+ return true;
+}
+
+int next_prime(int n) {
+ if (n <= 1)
+ return 2;
+ do {
+ n++;
+ } while (!is_prime(n));
+ return n;
+}
+
+void print_sexy_primes(int count) {
+ int a = 1;
+ while (count > 0) {
+ a = next_prime(a);
+ int b = a;
+ while (b < a+6)
+ b = next_prime(b);
+ if (b == a+6) {
+ printf("(%d, %d)\n", a, b);
+ count--;
+ }
+ }
+}
+
+int main() {
+ print_sexy_primes(10);
+}
diff --git a/challenge-022/paulo-custodio/c/ch-2.c b/challenge-022/paulo-custodio/c/ch-2.c
new file mode 100644
index 0000000000..05a0f0c9ef
--- /dev/null
+++ b/challenge-022/paulo-custodio/c/ch-2.c
@@ -0,0 +1,233 @@
+/*
+Challenge 022
+
+Task #2
+Write a script to implement Lempel-Ziv-Welch (LZW) compression algorithm.
+The script should have method to encode/decode algorithm. The wiki page
+explains the compression algorithm very nicely.
+*/
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "uthash.h"
+#include "utstring.h"
+#include "utarray.h"
+
+#define EOM '#'
+#define SYMBOLS "#ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+typedef struct dict {
+ char* key;
+ int id;
+ UT_hash_handle hh;
+} Dict;
+
+typedef struct lzw {
+ Dict* dict;
+ UT_array* symbols;
+} LZW;
+
+int bits_width(int n) {
+ int width = 0;
+ while (n > 0) {
+ n /= 2;
+ width++;
+ }
+ return width;
+}
+
+void output_bits(UT_string* result, int n, int width) {
+ UT_string* reverse_bits;
+ utstring_new(reverse_bits);
+
+ while (width > 0 || n > 0) {
+ utstring_printf(reverse_bits, "%c", '0' + (n & 1));
+ n /= 2;
+ width--;
+ }
+
+ for (const char* p = utstring_body(reverse_bits) + utstring_len(reverse_bits) - 1;
+ p >= utstring_body(reverse_bits); p--)
+ utstring_printf(result, "%c", *p);
+
+ utstring_free(reverse_bits);
+}
+
+int input_bits(const char** p, int width) {
+ int result = 0;
+ while (**p != '\0' && width-- > 0) {
+ result *= 2;
+ result += **p == '1' ? 1 : 0;
+ (*p)++;
+ }
+ return result;
+}
+
+void* check_mem(void* p) {
+ if (!p) {
+ fputs("out of memory", stderr);
+ exit(EXIT_FAILURE);
+ }
+ return p;
+}
+
+int lzw_last(LZW* lzw) {
+ return utarray_len(lzw->symbols) - 1;
+}
+
+int lzw_width(LZW* lzw) {
+ return bits_width(lzw_last(lzw));
+}
+
+int lzw_next_width(LZW* lzw) {
+ return bits_width(lzw_last(lzw) + 1);
+}
+
+void lzw_add(LZW* lzw, const char* seq) {
+ int id = lzw_last(lzw) + 1;
+
+ Dict* elt = check_mem(calloc(1, sizeof(Dict)));
+ elt->key = check_mem(strdup(seq));
+ elt->id = id;
+ HASH_ADD_KEYPTR(hh, lzw->dict, elt->key, strlen(elt->key), elt);
+
+ utarray_push_back(lzw->symbols, &seq);
+}
+
+LZW* lzw_new() {
+ LZW* lzw = check_mem(calloc(1, sizeof(LZW)));
+ utarray_new(lzw->symbols, &ut_str_icd);
+
+ for (const char* p = SYMBOLS; *p; p++) {
+ char seq[2];
+ seq[0] = *p;
+ seq[1] = '\0';
+ lzw_add(lzw, seq);
+ }
+
+ return lzw;
+}
+
+void lzw_free(LZW* lzw) {
+ Dict* elt, * tmp;
+
+ HASH_ITER(hh, lzw->dict, elt , tmp) {
+ HASH_DEL(lzw->dict, elt);
+ free(elt->key);
+ free(elt);
+ }
+
+ utarray_free(lzw->symbols);
+}
+
+void lzw_longest_match(LZW* lzw, UT_string* encoded, const char** p) {
+ UT_string* prefix;
+ utstring_new(prefix);
+
+ // find longest match
+ int len = 0;
+ while (len < strlen(*p)) {
+ utstring_clear(prefix);
+ utstring_printf(prefix, "%-.*s", len + 1, *p);
+ Dict* elt;
+ HASH_FIND_STR(lzw->dict, utstring_body(prefix), elt);
+ if (elt == NULL)
+ break;
+ len++;
+ }
+
+ utstring_clear(prefix);
+ utstring_printf(prefix, "%-.*s", len, *p);
+ (*p) += len;
+
+ Dict* elt;
+ HASH_FIND_STR(lzw->dict, utstring_body(prefix), elt);
+ assert(elt != NULL);
+ int code = elt->id;
+ int code_width = lzw_width(lzw);
+
+ // store new prefix in dictionary
+ if (**p != '\0') {
+ utstring_printf(prefix, "%c", **p);
+ lzw_add(lzw, utstring_body(prefix));
+ }
+
+ output_bits(encoded, code, code_width);
+ utstring_free(prefix);
+}
+
+void lzw_encode(LZW* lzw, UT_string* encoded, const char* text_) {
+ UT_string* text;
+ utstring_new(text);
+ for (const char* p = text_; *p; p++)
+ if (isalpha(*p))
+ utstring_printf(text, "%c", toupper(*p));
+ utstring_printf(text, "%c", EOM);
+
+ utstring_clear(encoded);
+ const char* p = utstring_body(text);
+ while (*p) {
+ lzw_longest_match(lzw, encoded, &p);
+ }
+
+ utstring_free(text);
+}
+
+void lzw_decode(LZW* lzw, UT_string* decoded, const char* text) {
+ const char* p = text;
+ utstring_clear(decoded);
+ while (*p) {
+ int code = input_bits(&p, lzw_width(lzw));
+ const char* seq = *(const char**)utarray_eltptr(lzw->symbols, code);
+ utstring_printf(decoded, "%s", seq);
+ if (*p) {
+ int next_width = lzw_next_width(lzw);
+ const char* p1 = p;
+ int next_code = input_bits(&p1, next_width);
+ const char* next_seq= *(const char**)utarray_eltptr(lzw->symbols, next_code);
+ UT_string* next_prefix;
+ utstring_new(next_prefix);
+ utstring_printf(next_prefix, "%s%c", seq, *next_seq);
+ lzw_add(lzw, utstring_body(next_prefix));
+ utstring_free(next_prefix);
+ }
+ }
+
+ // remove EOM
+ utstring_body(decoded)[utstring_len(decoded) - 1] = '\0';
+ utstring_len(decoded) = strlen(utstring_body(decoded));
+}
+
+void usage() {
+ fputs("usage: ch-2 encode|decode text", stderr);
+}
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ usage();
+ return EXIT_FAILURE;
+ }
+
+ UT_string* result;
+ utstring_new(result);
+ LZW* lzw = lzw_new();
+
+ if (strcmp(argv[1], "encode") == 0) {
+ lzw_encode(lzw, result, argv[2]);
+ }
+ else if (strcmp(argv[1], "decode") == 0) {
+ lzw_decode(lzw, result, argv[2]);
+ }
+ else {
+ usage();
+ return EXIT_FAILURE;
+ }
+
+ printf("%s\n", utstring_body(result));
+
+ utstring_free(result);
+ lzw_free(lzw);
+}
diff --git a/challenge-022/paulo-custodio/c/utarray.h b/challenge-022/paulo-custodio/c/utarray.h
new file mode 100644
index 0000000000..1fe8bc1c74
--- /dev/null
+++ b/challenge-022/paulo-custodio/c/utarray.h
@@ -0,0 +1,252 @@
+/*
+Copyright (c) 2008-2022, Troy D. Hanson https://troydhanson.github.io/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* a dynamic array implementation using macros
+ */
+#ifndef UTARRAY_H
+#define UTARRAY_H
+
+#define UTARRAY_VERSION 2.3.0
+
+#include <stddef.h> /* size_t */
+#include <string.h> /* memset, etc */
+#include <stdlib.h> /* exit */
+
+#ifdef __GNUC__
+#define UTARRAY_UNUSED __attribute__((__unused__))
+#else
+#define UTARRAY_UNUSED
+#endif
+
+#ifndef utarray_oom
+#define utarray_oom() exit(-1)
+#endif
+
+typedef void (ctor_f)(void *dst, const void *src);
+typedef void (dtor_f)(void *elt);
+typedef void (init_f)(void *elt);
+typedef struct {
+ size_t sz;
+ init_f *init;
+ ctor_f *copy;
+ dtor_f *dtor;
+} UT_icd;
+
+typedef struct {
+ unsigned i,n;/* i: index of next available slot, n: num slots */
+ UT_icd icd; /* initializer, copy and destructor functions */
+ char *d; /* n slots of size icd->sz*/
+} UT_array;
+
+#define utarray_init(a,_icd) do { \
+ memset(a,0,sizeof(UT_array)); \
+ (a)->icd = *(_icd); \
+} while(0)
+
+#define utarray_done(a) do { \
+ if ((a)->n) { \
+ if ((a)->icd.dtor) { \
+ unsigned _ut_i; \
+ for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
+ (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \
+ } \
+ } \
+ free((a)->d); \
+ } \
+ (a)->n=0; \
+} while(0)
+
+#define utarray_new(a,_icd) do { \
+ (a) = (UT_array*)malloc(sizeof(UT_array)); \
+ if ((a) == NULL) { \
+ utarray_oom(); \
+ } \
+ utarray_init(a,_icd); \
+} while(0)
+
+#define utarray_free(a) do { \
+ utarray_done(a); \
+ free(a); \
+} while(0)
+
+#define utarray_reserve(a,by) do { \
+ if (((a)->i+(by)) > (a)->n) { \
+ char *utarray_tmp; \
+ while (((a)->i+(by)) > (a)->n) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \
+ utarray_tmp=(char*)realloc((a)->d, (a)->n*(a)->icd.sz); \
+ if (utarray_tmp == NULL) { \
+ utarray_oom(); \
+ } \
+ (a)->d=utarray_tmp; \
+ } \
+} while(0)
+
+#define utarray_push_back(a,p) do { \
+ utarray_reserve(a,1); \
+ if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \
+ else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \
+} while(0)
+
+#define utarray_pop_back(a) do { \
+ if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \
+ else { (a)->i--; } \
+} while(0)
+
+#define utarray_extend_back(a) do { \
+ utarray_reserve(a,1); \
+ if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \
+ else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \
+ (a)->i++; \
+} while(0)
+
+#define utarray_len(a) ((a)->i)
+
+#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL)
+#define _utarray_eltptr(a,j) ((void*)((a)->d + ((a)->icd.sz * (j))))
+
+#define utarray_insert(a,p,j) do { \
+ if ((j) > (a)->i) utarray_resize(a,j); \
+ utarray_reserve(a,1); \
+ if ((j) < (a)->i) { \
+ memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \
+ ((a)->i - (j))*((a)->icd.sz)); \
+ } \
+ if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \
+ else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \
+ (a)->i++; \
+} while(0)
+
+#define utarray_inserta(a,w,j) do { \
+ if (utarray_len(w) == 0) break; \
+ if ((j) > (a)->i) utarray_resize(a,j); \
+ utarray_reserve(a,utarray_len(w)); \
+ if ((j) < (a)->i) { \
+ memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \
+ _utarray_eltptr(a,j), \
+ ((a)->i - (j))*((a)->icd.sz)); \
+ } \
+ if ((a)->icd.copy) { \
+ unsigned _ut_i; \
+ for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \
+ (a)->icd.copy(_utarray_eltptr(a, (j) + _ut_i), _utarray_eltptr(w, _ut_i)); \
+ } \
+ } else { \
+ memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \
+ utarray_len(w)*((a)->icd.sz)); \
+ } \
+ (a)->i += utarray_len(w); \
+} while(0)
+
+#define utarray_resize(dst,num) do { \
+ unsigned _ut_i; \
+ if ((dst)->i > (unsigned)(num)) { \
+ if ((dst)->icd.dtor) { \
+ for (_ut_i = (num); _ut_i < (dst)->i; ++_ut_i) { \
+ (dst)->icd.dtor(_utarray_eltptr(dst, _ut_i)); \
+ } \
+ } \
+ } else if ((dst)->i < (unsigned)(num)) { \
+ utarray_reserve(dst, (num) - (dst)->i); \<