%{ /* -*- C -*- */ # include # include typedef struct StringList { char *string; struct StringList *next; } StringList; StringList *newString(char *string, StringList *list); void pushString(StringList **list, char *string); char *popString(StringList **list); StringList *urls= 0; FILE *yyin= 0; # define YY_INPUT(buf, result, max_size) \ { \ int yyc= fgetc(yyin); \ result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1); \ } %} document = (href | .)* !. href = '<' - [aA] (!HREF .)* HREF - '=' - '"' < (!'"' .)+ > '"' (!'>' .)* '>' { pushString(&urls, yytext); } HREF = [hH][rR][eF][fF] - = (' ' | '\t' | '\n' | '\r')* %% int verbose= 0; StringList *errorFiles= 0; StringList *errorURLs= 0; StringList *errorMessages= 0; StringList *newString(char *string, StringList *list) { StringList *s= calloc(1, sizeof(StringList)); s->string= strdup(string); s->next= list; return s; } void pushString(StringList **list, char *string) { *list= newString(string, *list); } char *popString(StringList **list) { StringList *s= *list; char *string; if (!s) { fprintf(stderr, "string list underflow\n"); exit(1); } *list= s->next; string= s->string; free(s); return string; } void error(char *file, char *url, char *message) { pushString(&errorFiles, file); pushString(&errorURLs, url); pushString(&errorMessages, message); fprintf(stderr, "%s: %s: %s\n", file, message, url); } void checklink(char *file, char *url) { if ('#' != url[0]) { CURL *curl= curl_easy_init(); CURLcode code; long response; curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30); curl_easy_setopt(curl, CURLOPT_NOBODY, 1); if ((code= curl_easy_perform(curl))) error(file, url, (char *)curl_easy_strerror(code)); else { if ((code= curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response))) error(file, url, (char *)curl_easy_strerror(code)); else { if (verbose) printf("%ld %s\n", response, url); if (404 == response) error(file, url, "ERROR 404"); } } curl_easy_cleanup(curl); } } void usage(char *program) { fprintf(stderr, "usage: %s [option] filename...\n", program); fprintf(stderr, " -v show response code for every URL\n"); } int main(int argc, char **argv) { int i; for (i= 1; i < argc; ++i) { if ('-' == !strncmp(argv[i], "-h", 2) || !strncmp(argv[i], "--h", 3)) usage(argv[0]); else if (!strcmp(argv[i], "-v")) verbose= 1; else if (!(yyin= fopen(argv[i], "r"))) perror(argv[i]); else { fprintf(stderr, "checking %s\n", argv[i]); yyparse(); if (!feof(yyin)) { error(argv[i], "?", "parse error"); fprintf(stderr, "parse error at line %d\n"); } else while (urls) checklink(argv[i], popString(&urls)); fclose(yyin); } } if (verbose && errorFiles) { fprintf(stderr, "\nErrors detected:\n"); while (errorFiles) fprintf(stderr, "%s: %s: %s\n", popString(&errorFiles), popString(&errorMessages), popString(&errorURLs)); } return 0; }