aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbigail <abigail@abigail.be>2021-02-05 17:07:18 +0100
committerAbigail <abigail@abigail.be>2021-02-05 18:44:55 +0100
commit20b322efb8bfcd4055c5f84496e54cde2db3a51a (patch)
tree69695704eea270bf9ac2a10cf58a2474a6f1a98a
parent9ad3b511c7ff826bfeeb646f356bb17df7e50957 (diff)
downloadperlweeklychallenge-club-20b322efb8bfcd4055c5f84496e54cde2db3a51a.tar.gz
perlweeklychallenge-club-20b322efb8bfcd4055c5f84496e54cde2db3a51a.tar.bz2
perlweeklychallenge-club-20b322efb8bfcd4055c5f84496e54cde2db3a51a.zip
C solution for week 98, part 1
-rw-r--r--challenge-098/abigail/README.md1
-rw-r--r--challenge-098/abigail/c/ch-1.c220
2 files changed, 221 insertions, 0 deletions
diff --git a/challenge-098/abigail/README.md b/challenge-098/abigail/README.md
index 3b8c4e5800..56e481bb08 100644
--- a/challenge-098/abigail/README.md
+++ b/challenge-098/abigail/README.md
@@ -55,6 +55,7 @@ Output:
### Solutions
* [AWK](awk/ch-1.awk)
* [Bash](bash/ch-1.sh)
+* [C](c/ch-1.ch)
* [Perl](perl/ch-1.pl)
### Blog
diff --git a/challenge-098/abigail/c/ch-1.c b/challenge-098/abigail/c/ch-1.c
new file mode 100644
index 0000000000..8aee103290
--- /dev/null
+++ b/challenge-098/abigail/c/ch-1.c
@@ -0,0 +1,220 @@
+# include <stdlib.h>
+# include <stdio.h>
+# include <string.h>
+# include <ctype.h>
+# include <limits.h>
+
+/*
+ * See ../README.md
+ */
+
+/*
+ * Run as: cc -o ch-1.o ch-1.c; ./ch-1.o < input-file
+ */
+
+/*
+ * Copied from https://gist.github.com/w-vi/7e98342181776162b1a3
+ */
+char * slurpfile (char * filename) {
+ FILE * fp;
+ char * source;
+ long bufsize;
+ size_t len;
+ if ((fp = fopen (filename, "r")) == NULL) {
+ fprintf (stderr, "Failed to open %s\n", filename);
+ exit (1);
+ }
+ /*
+ * Get the size of the file:
+ * - seek to the end of the file
+ * - use ftell to get the offset from the start
+ * - seek back to the beginning
+ */
+ if (fseek (fp, 0L, SEEK_END) != 0) {
+ fprintf (stderr, "seek() failed for %s\n", filename);
+ exit (1);
+ }
+ if ((bufsize = ftell (fp)) == -1) {
+ fprintf (stderr, "ftell() failed for %s\n", filename);
+ exit (1);
+ }
+ if (fseek (fp, 0L, SEEK_SET) != 0) {
+ fprintf (stderr, "seek() failed for %s\n", filename);
+ exit (1);
+ }
+
+ /*
+ * Allocate memory for content of the file
+ */
+ if ((source = (char *) malloc (sizeof (char) * (bufsize + 1))) == NULL) {
+ fprintf (stderr, "malloc() failed for %s\n", filename);
+ exit (1);
+ }
+
+ /*
+ * And read it in
+ */
+ if ((len = fread (source, sizeof (char), bufsize, fp)) == 0) {
+ fprintf (stderr, "fread() failed for %s\n", filename);
+ exit (1);
+ }
+ source [++ len] = '\0';
+
+ return source;
+}
+
+/*
+ * Use four arrays:
+ * - filenames: names of files read
+ * - content: pointers to content of files read
+ * - content_ptr: pointers to unreturned content
+ * - content_size: number of characters not returned yet
+ */
+size_t read_files = 0;
+char ** filenames = NULL;
+char ** content = NULL;
+char ** content_ptr = NULL;
+size_t * content_size = NULL;
+
+char * readN (char * filename, int amount) {
+ ssize_t found = -1;
+ char * out;
+ /*
+ * Check whether we've already found the file --
+ * if so, set its position in "found".
+ */
+ for (size_t i = 0; i < read_files; i ++) {
+ if (strncmp (filename, filenames [i], PATH_MAX) == 0) {
+ /*
+ * Found the file
+ */
+ found = i;
+ break;
+ }
+ }
+
+ /*
+ * Not found; all filename, content of file, and size to
+ * the end of the arrays.
+ */
+ if (found < 0) {
+ found = read_files ++;
+ /*
+ * Allocate memory
+ */
+ if ((filenames = (char **)
+ realloc (filenames, read_files * sizeof (char *))) == NULL) {
+ fprintf (stderr, "malloc() failed for %s\n", filename);
+ exit (1);
+ }
+ if ((content = (char **)
+ realloc (content, read_files * sizeof (char *))) == NULL) {
+ fprintf (stderr, "malloc() failed for %s\n", filename);
+ exit (1);
+ }
+ if ((content_ptr = (char **)
+ realloc (content_ptr, read_files * sizeof (char *))) == NULL) {
+ fprintf (stderr, "malloc() failed for %s\n", filename);
+ exit (1);
+ }
+ if ((content_size = (size_t *)
+ realloc (content_size, read_files * sizeof (size_t))) == NULL) {
+ fprintf (stderr, "malloc() failed for %s\n", filename);
+ exit (1);
+ }
+
+ /*
+ * Set data
+ */
+ if ((filenames [found] = (char *)
+ malloc (sizeof (char) * (strlen (filename) + 1))) == NULL) {
+ fprintf (stderr, "malloc() failed for %s\n", filename);
+ exit (1);
+ }
+ stpncpy (filenames [found], filename, strlen (filename));
+ filenames [found] [strlen (filename)] = '\0';
+ content [found] = slurpfile (filename);
+ content_ptr [found] = content [found];
+ content_size [found] = strlen (content [found]);
+
+ /*
+ * Remove any trailing new lines
+ */
+ while (content [found] [content_size [found] - 1] == '\n') {
+ content [found] [-- content_size [found]] = '\0';
+ }
+ }
+ /*
+ * Now 'found' points to the place where the content
+ * of the file is.
+ */
+
+ /*
+ * Cannot return more than we have.
+ */
+ if (content_size [found] < amount) {
+ amount = content_size [found];
+ }
+ /*
+ * Allocate memory for the return value
+ */
+ if ((out = (char *) malloc (sizeof (char) * (amount + 1))) == NULL) {
+ fprintf (stderr, "malloc() failed for %s\n", filename);
+ exit (1);
+ }
+ /*
+ * Copy the amount of data, make sure it's NUL terminated.
+ */
+ stpncpy (out, content_ptr [found], amount);
+ out [amount] = '\0';
+
+ /*
+ * Adjust the pointer and size left
+ */
+ content_ptr [found] += amount;
+ content_size [found] -= amount;
+
+ return out;
+}
+
+
+
+int main (void) {
+ char * line = NULL;
+ size_t len = 0;
+ size_t strlen;
+
+ /*
+ * Iterate over the lines of input; parse each line into
+ * a file name and an amount. Call readN for each line.
+ */
+ while ((strlen = getline (&line, &len, stdin)) != -1) {
+ char * line_ptr = line;
+ char * filename;
+ int amount;
+ if ((filename = (char *) malloc (PATH_MAX * sizeof (char))) == NULL) {
+ fprintf (stderr, "malloc() failed\n");
+ exit (1);
+ }
+ if (sscanf (line_ptr, "%s %d", filename, &amount) != 2) {
+ fprintf (stderr, "Could not parse input\n");
+ exit (1);
+ }
+ printf ("%s\n", readN (filename, amount));
+ free (filename);
+ }
+ /*
+ * Release memory
+ */
+ free (line);
+ for (size_t i = 0; i < read_files; i ++) {
+ free (filenames [i]);
+ free (content [i]);
+ }
+ free (filenames);
+ free (content);
+ free (content_ptr);
+ free (content_size);
+
+ return (0);
+}