diff options
| author | Abigail <abigail@abigail.be> | 2021-02-05 17:07:18 +0100 |
|---|---|---|
| committer | Abigail <abigail@abigail.be> | 2021-02-05 18:44:55 +0100 |
| commit | 20b322efb8bfcd4055c5f84496e54cde2db3a51a (patch) | |
| tree | 69695704eea270bf9ac2a10cf58a2474a6f1a98a | |
| parent | 9ad3b511c7ff826bfeeb646f356bb17df7e50957 (diff) | |
| download | perlweeklychallenge-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.md | 1 | ||||
| -rw-r--r-- | challenge-098/abigail/c/ch-1.c | 220 |
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); +} |
