/* * Convert a file containing ASCII integers into packed BCD. */ #define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include static int worker(char*, size_t, char*, size_t); static int nextchar(char*, size_t, size_t*, ssize_t*); extern int main() { struct stat st; size_t inbuflen, outbuflen; char *inbuf, *outbuf; if (fstat(STDIN_FILENO, &st) == -1) { perror("Cannot stat stdin"); return EXIT_FAILURE; } inbuflen = (size_t)st.st_blksize; if (fstat(STDOUT_FILENO, &st) == -1) { perror("Cannot stat stdout"); return EXIT_FAILURE; } outbuflen = (size_t)st.st_blksize; inbuf = malloc(inbuflen); outbuf = malloc(outbuflen); if (inbuf == NULL || outbuf == NULL) { perror("Cannot malloc"); return EXIT_FAILURE; } return worker(inbuf, inbuflen, outbuf, outbuflen); } static int worker(char *inbuf, size_t inbuflen, char *outbuf, size_t outbuflen) { size_t inidx = 0, outidx = 0; ssize_t incount = 0, outcount; int high, low; errno = 0; for (;;) { high = nextchar(inbuf, inbuflen, &inidx, &incount); if (high == EOF) break; low = nextchar(inbuf, inbuflen, &inidx, &incount); if (low == EOF) break; outbuf[outidx++] = high << 4 | low; if (outidx < outbuflen) continue; outidx = 0; outcount = write(STDOUT_FILENO, outbuf, outbuflen); if (outcount < 0) { perror("Error writing to stdout"); break; } else if (outcount < outbuflen) { fprintf(stderr, "Short write on stdout"); return 1; } } return errno != 0; } static int nextchar(char *inbuf, size_t inbuflen, size_t *inidx, ssize_t *incount) { do { if (*inidx < *incount) continue; *inidx = 0; *incount = read(STDIN_FILENO, inbuf, inbuflen); if (*incount < 0) perror("Error reading stdin"); if (*incount <= 0) return EOF; } while (!isdigit(inbuf[(*inidx)++])); return (unsigned char)inbuf[*inidx - 1] - '0'; }