1 /* Id: manpage.c,v 1.6 2013/12/31 03:41:14 schwarze Exp */ 2 /* 3 * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv> 4 * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 #ifdef HAVE_CONFIG_H 19 #include "config.h" 20 #endif 21 22 #include <assert.h> 23 #include <getopt.h> 24 #include <limits.h> 25 #include <stdint.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #include "manpath.h" 32 #include "mansearch.h" 33 34 static void show(const char *, const char *); 35 36 int 37 main(int argc, char *argv[]) 38 { 39 int ch, term; 40 size_t i, sz, len; 41 struct mansearch search; 42 struct manpage *res; 43 char *conf_file, *defpaths, *auxpaths, *cp; 44 char buf[PATH_MAX]; 45 const char *cmd; 46 struct manpaths paths; 47 char *progname; 48 extern char *optarg; 49 extern int optind; 50 51 term = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO); 52 53 progname = strrchr(argv[0], '/'); 54 if (progname == NULL) 55 progname = argv[0]; 56 else 57 ++progname; 58 59 auxpaths = defpaths = conf_file = NULL; 60 memset(&paths, 0, sizeof(struct manpaths)); 61 memset(&search, 0, sizeof(struct mansearch)); 62 63 while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:"))) 64 switch (ch) { 65 case ('C'): 66 conf_file = optarg; 67 break; 68 case ('M'): 69 defpaths = optarg; 70 break; 71 case ('m'): 72 auxpaths = optarg; 73 break; 74 case ('S'): 75 search.arch = optarg; 76 break; 77 case ('s'): 78 search.sec = optarg; 79 break; 80 default: 81 goto usage; 82 } 83 84 argc -= optind; 85 argv += optind; 86 87 if (0 == argc) 88 goto usage; 89 90 search.deftype = TYPE_Nm | TYPE_Nd; 91 92 manpath_parse(&paths, conf_file, defpaths, auxpaths); 93 ch = mansearch(&search, &paths, argc, argv, NULL, &res, &sz); 94 manpath_free(&paths); 95 96 if (0 == ch) 97 goto usage; 98 99 if (0 == sz) { 100 free(res); 101 return(EXIT_FAILURE); 102 } else if (1 == sz && term) { 103 i = 1; 104 goto show; 105 } else if (NULL == res) 106 return(EXIT_FAILURE); 107 108 for (i = 0; i < sz; i++) { 109 printf("%6zu %s: %s\n", 110 i + 1, res[i].names, res[i].desc); 111 free(res[i].names); 112 free(res[i].desc); 113 free(res[i].output); 114 } 115 116 if (0 == term) { 117 for (i = 0; i < sz; i++) 118 free(res[i].file); 119 free(res); 120 return(EXIT_SUCCESS); 121 } 122 123 i = 1; 124 printf("Enter a choice [1]: "); 125 fflush(stdout); 126 127 if (NULL != (cp = fgetln(stdin, &len))) 128 if ('\n' == cp[--len] && len > 0) { 129 cp[len] = '\0'; 130 if ((i = atoi(cp)) < 1 || i > sz) 131 i = 0; 132 } 133 134 if (0 == i) { 135 for (i = 0; i < sz; i++) 136 free(res[i].file); 137 free(res); 138 return(EXIT_SUCCESS); 139 } 140 show: 141 cmd = res[i - 1].form ? "mandoc" : "cat"; 142 strlcpy(buf, res[i - 1].file, PATH_MAX); 143 for (i = 0; i < sz; i++) 144 free(res[i].file); 145 free(res); 146 147 show(cmd, buf); 148 /* NOTREACHED */ 149 usage: 150 fprintf(stderr, "usage: %s [-C conf] " 151 "[-M paths] " 152 "[-m paths] " 153 "[-S arch] " 154 "[-s section] " 155 "expr ...\n", 156 progname); 157 return(EXIT_FAILURE); 158 } 159 160 static void 161 show(const char *cmd, const char *file) 162 { 163 int fds[2]; 164 pid_t pid; 165 166 if (-1 == pipe(fds)) { 167 perror(NULL); 168 exit(EXIT_FAILURE); 169 } 170 171 if (-1 == (pid = fork())) { 172 perror(NULL); 173 exit(EXIT_FAILURE); 174 } else if (pid > 0) { 175 dup2(fds[0], STDIN_FILENO); 176 close(fds[1]); 177 cmd = NULL != getenv("MANPAGER") ? 178 getenv("MANPAGER") : 179 (NULL != getenv("PAGER") ? 180 getenv("PAGER") : "more"); 181 execlp(cmd, cmd, (char *)NULL); 182 perror(cmd); 183 exit(EXIT_FAILURE); 184 } 185 186 dup2(fds[1], STDOUT_FILENO); 187 close(fds[0]); 188 execlp(cmd, cmd, file, (char *)NULL); 189 perror(cmd); 190 exit(EXIT_FAILURE); 191 } 192