/* bagmatch.c, mostly by GPT-5 Mini. * * Print all words from a dictionary file whose letters (single-byte ASCII) * form the same multiset ("bag") as the first command-line argument. * * Usage: ./bagmatch KEYWORD DICTIONARY_FILE * * Constraints & behavior per request: * - Words and KEYWORD are assumed to contain only letters; no validity checks. * - Maximum input word length is 64 bytes; program exits with error if exceeded. * - Sort letters in a word using an insertion-sort subroutine into canonical order. * - Compare canonical forms via memcmp. * - Use stdio for I/O; be fast and avoid dynamic allocation. */ #include #include #include #define MAXWORD 64 /* insertion_sort_chars: * Sorts n bytes in-place (array of unsigned char) using insertion sort. * This is optimized for small fixed-size keys (<=64). */ static void insertion_sort_chars(unsigned char *a, size_t n) { for (size_t i = 1; i < n; ++i) { unsigned char key = a[i]; size_t j = i; while (j > 0 && a[j - 1] > key) { a[j] = a[j - 1]; --j; } a[j] = key; } } int main(int argc, char *argv[]) { if (argc != 3) { fputs("Usage: bagmatch KEYWORD DICTIONARY_FILE\n", stderr); return 2; } unsigned char keybuf[MAXWORD]; size_t keylen = strlen(argv[1]); if (keylen > MAXWORD) { fputs("Error: keyword too long (max 64 bytes)\n", stderr); return 2; } /* copy then sort into canonical form */ memcpy(keybuf, argv[1], keylen); insertion_sort_chars(keybuf, keylen); FILE *f = fopen(argv[2], "rb"); if (!f) { perror(argv[2]); return 2; } /* Read file line-by-line, each word followed by '\n' including last. */ char inbuf[MAXWORD + 2]; /* allow room to detect overflow and newline */ for (;;) { if (!fgets(inbuf, MAXWORD + 2, f)) { if (feof(f)) break; perror("fgets"); fclose(f); return 2; } /* strchrnul */ size_t bufpos = 0; while (inbuf[bufpos] != '\n' && inbuf[bufpos]) bufpos++; /* word is in inbuf[0..bufpos-1] */ if (bufpos > MAXWORD) { fprintf(stderr, "Error: input word too long (max %d bytes)\n", MAXWORD); fclose(f); return 2; } /* Test words of the right length further. */ if (bufpos == keylen) { /* sort a copy so we don't disturb original for printing */ unsigned char work[MAXWORD]; memcpy(work, inbuf, bufpos); insertion_sort_chars(work, bufpos); if (memcmp(work, keybuf, keylen) == 0) { /* match: print original word (as bytes) followed by newline */ if (fwrite(inbuf, 1, bufpos, stdout) != bufpos || putchar('\n') == EOF) { perror("write"); fclose(f); return 2; } } } } fclose(f); return 0; }