#include #include #include #include #include #include #include #include #include const char* cmdname; /* print error message and exit */ void die(const char* reason) { stralloc msg = {0}; if (stralloc_copys(&msg, cmdname) && stralloc_cats(&msg, ": ") && stralloc_cats(&msg, strerror(errno)) && stralloc_cats(&msg, ": ") && stralloc_cats(&msg, reason) && stralloc_cats(&msg, "\n")) { write(2, msg.s, msg.len); } exit(1); } /* print usage message and exit */ void usage() { stralloc usage = {0}; if (stralloc_copys(&usage, "Usage: ") && stralloc_cats(&usage, cmdname) && stralloc_cats(&usage, " source\n")) { write(2, usage.s, usage.len); } exit(1); } /* print interval [cp, endp) to standard output and append a newline if none is included at the end of the comment */ void print(const char* cp, const char* endp) { char lastch = endp[-1]; while (cp < endp) { ssize_t nbytes = write(1, cp, endp - cp); if (nbytes < 0) { die("write error"); } cp += nbytes; } if (lastch != '\n') { write(1, "\n", 1); } } /* invoke print for each comment found in [cp, endp) */ void extract_comments(const char* cp, const char* endp) { enum { START, /* initial state */ SLASH1, /* '/' seen, could start comment */ SLASH2, /* "//" seen, within comment */ STAR1, /* '/', '*' seen, within comment */ STAR2, /* '/', '*', ..., '*' seen */ } state = START; const char* comment = 0; while (cp < endp) { char ch = *cp; switch (state) { case START: if (ch == '/') state = SLASH1; break; case SLASH1: if (ch == '/') { state = SLASH2; comment = cp - 1; } else if (ch == '*') { state = STAR1; comment = cp - 1; } else { state = START; } break; case SLASH2: if (ch == '\n') { print(comment, cp+1); state = START; } break; case STAR1: if (ch == '*') { state = STAR2; } break; case STAR2: if (ch == '/') { print(comment, cp+1); state = START; } else { state = STAR1; } break; } ++cp; } if (state == SLASH2 || state == STAR1 || state == STAR2) { /* print unfinished comment */ print(comment, cp); } } int main(int argc, char* argv[]) { cmdname = *argv++; --argc; if (argc != 1) usage(); const char* file = *argv++; --argc; int fd = open(file, O_RDONLY); if (fd < 0) die(file); struct stat statbuf; if (fstat(fd, &statbuf) < 0) die(file); off_t nbytes = statbuf.st_size; char* buf = (char*) mmap(0, nbytes, PROT_READ, MAP_SHARED, fd, 0); if (buf == MAP_FAILED) die(file); extract_comments(buf, buf + nbytes); if (munmap((caddr_t) buf, nbytes) < 0) die(file); if (close(fd) < 0) die(file); }