/* Appends a character to the command buffer */ static void append_char(int ch) { /* Make sure there's enough room */ if (cmd_index >= cmd_length) { xdprintf(3, "growing buffer\n"); /* Double the buffer size */ cmd_length *= 2; cmd_buffer = realloc(cmd_buffer, cmd_length); if (cmd_buffer == NULL) { perror("realloc() failed"); exit(1); } } cmd_buffer[cmd_index++] = ch; }
void timeval_xdprint(char *s, struct timeval tv) { xdprintf("%s %d.%06d\n", s, tv.tv_sec, tv.tv_usec); }
/* Read the URL from a file and use it to invoke a browser */ int main(int argc, char *argv[]) { const char *browser; char buffer[MAX_URL_SIZE + 1]; struct stat statbuf; char *url = NULL; char *filename = NULL; FILE *file; size_t length, i; const char *point; /* Extract the program name from argv[0] */ progname = strrchr(argv[0], '/'); if (progname == NULL) { progname = argv[0]; } else { progname++; } /* Get the browser string from the environment */ browser = getenv(ENV_BROWSER); if (browser == NULL) { browser = DEF_BROWSER; } for (;;) { int choice; #if defined(HAVE_GETOPT_LONG) choice = getopt_long(argc, argv, OPTIONS, long_options, NULL); #else choice = getopt(argc, argv, OPTIONS); #endif /* End of options? */ if (choice < 0) { break; } /* Which option is it? */ switch (choice) { case 'b': /* --browser= or -b */ browser = optarg; break; case 'd': /* --debug= or -d */ if (optarg == NULL) { verbosity++; } else { verbosity = atoi(optarg); } break; case 'h': /* --help or -h */ usage(); exit(0); case 'u': /* --url= or -u */ /* Determine if we should view a local file or a remote one */ if (stat(optarg, &statbuf) < 0) { xdprintf(2, "%s: unable to stat file: %s\n", progname, optarg); url = strdup(optarg); } else if ((statbuf.st_mode & S_IRUSR) == 0) { xdprintf(2, "%s: unable to read file: %s\n", progname, optarg); url = strdup(optarg); } else { xdprintf(3, "%s: creating file URL: %s\n", progname, optarg); if (optarg[0] == '/') { length = sizeof(FILE_URL_PREFIX) + strlen(optarg); url = malloc(length); if (url == NULL) { perror("malloc() failed"); exit(1); } snprintf(url, length, FILE_URL_PREFIX "%s", optarg); } else { /* Construct an absolute path */ if (getcwd(buffer, MAX_URL_SIZE) == NULL) { perror("Unable to determine current directory"); exit(1); } length = sizeof(FILE_URL_PREFIX) + strlen(buffer) + 1 + strlen(optarg); url = malloc(length); if (url == NULL) { perror("malloc() failed"); exit(1); } snprintf(url, length, FILE_URL_PREFIX "%s/%s", buffer, optarg); } } xdprintf(2, "%s: raw URL: %s\n", progname, url); break; case 'v': /* --version or -v */ printf(PACKAGE " show-url version " VERSION "\n"); exit(0); case '?': /* Unsupported option */ usage(); exit(1); default: /* Trouble */ abort(); } } /* If no URL or filename provided then read from stdin */ if (url == NULL) { if (optind < argc) { /* Get the filename */ filename = argv[optind++]; /* Treat '-' as a synonym for stdin */ if (strcmp(filename, "-") == 0) { filename = NULL; } } } /* Make sure there are no more arguments */ if (optind < argc) { usage(); exit(1); } /* Extract the URL from the file */ if (url == NULL) { if (filename == NULL) { xdprintf(3, "%s: reading URL from stdin\n", progname); filename = "<stdin>"; file = stdin; } else { xdprintf(3, "%s: reading URL from %s\n", progname, filename); /* Read the URL from the file */ file = fopen(filename, "r"); if (file == NULL) { perror("Unable to open URL file"); exit(1); } } /* Read up to MAX_URL_SIZE bytes of it */ length = fread(buffer, 1, MAX_URL_SIZE, file); /* Find the first CR or LF and truncate the string there. */ for (i = 0; i < length; i++) { if (buffer[i] == '\r' || buffer[i] == '\n') { break; } } buffer[i] = '\0'; xdprintf(2, "%s: raw URL: %s\n", progname, buffer); /* Clean up */ fclose(file); /* Duplicate its contents */ url = strdup(buffer); if (url == NULL) { perror("malloc() failed"); exit(1); } strcpy(url, buffer); } /* Initialize the command buffer */ cmd_length = INIT_CMD_SIZE; cmd_buffer = malloc(cmd_length); if (cmd_buffer == NULL) { perror("malloc() failed"); exit(1); } /* Attempt to open a browser */ point = browser; while (*point != '\0') { point = invoke(point, url); if (point == NULL) { exit(0); } } /* Clean up */ free(url); exit(1); }
/* Invoke the browser on the given URL */ const char * invoke(const char *browser, const char *url) { int did_subst = 0; const char *point = browser; int quote_count = 0; int status; /* Reset the buffer */ cmd_index = 0; /* Copy from the browser string */ for (;;) { int ch = *point; switch (ch) { case '\0': case ':': /* End of the browser string. Insert the URL if we * haven't done so already */ if (!did_subst) { append_char(' '); append_url(url, quote_count); } /* Null-terminate the command */ append_char('\0'); /* Invoke the command */ xdprintf(1, "exec: %s\n", cmd_buffer); status = system(cmd_buffer); if (status < 0) { perror("fork() failed"); exit(1); } /* If successful return NULL */ if (WEXITSTATUS(status) == 0) { xdprintf(2, "ok\n"); return NULL; } xdprintf(2, "failed: %d\n", WEXITSTATUS(status)); return ch == '\0' ? point : point + 1; case '"': /* Toggle double-quotes if appropriate */ if (quote_count == 2) { quote_count = 0; } else if (quote_count == 0) { quote_count = 2; } append_char(ch); break; case '\'': /* Toggle single-quotes if appropriate */ if (quote_count == 1) { quote_count = 0; } else if (quote_count == 0) { quote_count = 1; } append_char(ch); break; case '%': /* %-escapes */ ch = point[1]; /* Watch for the URL substitution */ if (ch == 's') { append_url(url, quote_count); /* Skip ahead */ did_subst = 1; point++; break; } /* Watch for odd EOF */ if (ch == '\0') { append_char('%'); break; } /* Otherwise drop the initial % */ append_char(ch); point++; break; default: append_char(ch); break; } point++; } }