1/* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: --- 13 unchanged lines hidden (view full) --- 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * Author: Hartmut Brandt <harti@freebsd.org> 28 */ 29#include <sys/cdefs.h> |
30__FBSDID("$FreeBSD: head/sbin/atm/atmconfig/main.c 132493 2004-07-21 09:42:56Z harti $"); |
31 32#include <sys/types.h> 33#include <sys/sysctl.h> 34#include <netdb.h> 35#include <stdarg.h> 36#include <ctype.h> 37#include <limits.h> |
38#include <stdint.h> 39#include <fnmatch.h> 40#include <dirent.h> |
41#include "atmconfig.h" 42#include "private.h" 43 44/* verbosity level */ 45int verbose; 46 47/* notitle option */ 48static int notitle; --- 17 unchanged lines hidden (view full) --- 66 67static int 68substr(const char *s1, const char *s2) 69{ 70 return (strlen(s1) <= strlen(s2) && strncmp(s1, s2, strlen(s1)) == 0); 71} 72 73/* |
74 * Current help file state 75 */ 76struct help_file { 77 int file_state; /* 0:looking for main file, 1:found, 2:other */ 78 const char *p_start; /* current path pointer */ 79 const char *p_end; /* end of current path in path */ 80 char *dirname; /* directory name */ 81 DIR *dir; /* open directory */ 82 char *fname; /* current filename */ 83 FILE *fp; /* open file */ 84 char line[LINE_MAX]; /* current line */ 85 u_int fcnt; /* count of files found */ 86}; 87 88struct help_pos { 89 off_t pos; /* file position */ 90 u_int fcnt; /* number of file */ 91 char *fname; /* name of file */ 92 const char *p_start; /* current path pointer */ 93 const char *p_end; /* end of current path in path */ 94}; 95 96static int 97help_next_file(struct help_file *hp) 98{ 99 const char *fpat; 100 struct dirent *ent; 101 102 if (hp->file_state == 3) 103 return (-1); 104 105 if (hp->file_state == 0) 106 fpat = FILE_HELP; 107 else 108 fpat = FILE_HELP_OTHERS; 109 110 if (hp->file_state == 0 || hp->file_state == 1) { 111 /* start from beginning */ 112 hp->p_start = PATH_HELP; 113 hp->file_state++; 114 } 115 116 try_file: 117 if (hp->dir != NULL) { 118 /* directory open (must be state 2) */ 119 while ((ent = readdir(hp->dir)) != NULL) { 120 if (fnmatch(fpat, ent->d_name, FNM_NOESCAPE) != 0) 121 continue; 122 if (asprintf(&hp->fname, "%s/%s", hp->dirname, 123 ent->d_name) == -1) 124 err(1, NULL); 125 if ((hp->fp = fopen(hp->fname, "r")) != NULL) { 126 hp->fcnt++; 127 return (0); 128 } 129 free(hp->fname); 130 } 131 /* end of directory */ 132 closedir(hp->dir); 133 hp->dir = NULL; 134 free(hp->dirname); 135 goto next_path; 136 } 137 138 /* nothing open - advanc to new path element */ 139 try_path: 140 for (hp->p_end = hp->p_start; *hp->p_end != '\0' && 141 *hp->p_end != ':'; hp->p_end++) 142 ; 143 144 if (asprintf(&hp->dirname, "%.*s", (int)(hp->p_end - hp->p_start), 145 hp->p_start) == -1) 146 err(1, NULL); 147 148 if (hp->file_state == 1) { 149 /* just try to open */ 150 if (asprintf(&hp->fname, "%s/%s", hp->dirname, fpat) == -1) 151 err(1, NULL); 152 if ((hp->fp = fopen(hp->fname, "r")) != NULL) { 153 hp->fcnt++; 154 return (0); 155 } 156 free(hp->fname); 157 158 goto next_path; 159 } 160 161 /* open directory */ 162 if ((hp->dir = opendir(hp->dirname)) != NULL) 163 goto try_file; 164 165 free(hp->dirname); 166 167 next_path: 168 hp->p_start = hp->p_end; 169 if (*hp->p_start == '\0') { 170 /* end of path */ 171 if (hp->file_state == 1) 172 errx(1, "help file not found"); 173 return (-1); 174 } 175 hp->p_start++; 176 goto try_path; 177 178} 179 180/* 181 * Save current file position 182 */ 183static void 184help_file_tell(struct help_file *hp, struct help_pos *pos) 185{ 186 if (pos->fname != NULL) 187 free(pos->fname); 188 if ((pos->fname = strdup(hp->fname)) == NULL) 189 err(1, NULL); 190 pos->fcnt = hp->fcnt; 191 pos->p_start = hp->p_start; 192 pos->p_end = hp->p_end; 193 if ((pos->pos = ftello(hp->fp)) == -1) 194 err(1, "%s", pos->fname); 195} 196 197/* 198 * Go to that position 199 * 200 * We can go either to the original help file or back in the current file. 201 */ 202static void 203help_file_seek(struct help_file *hp, struct help_pos *pos) 204{ 205 hp->p_start = pos->p_start; 206 hp->p_end = pos->p_end; 207 hp->fcnt = pos->fcnt; 208 209 if (hp->dir != NULL) { 210 free(hp->dirname); 211 closedir(hp->dir); 212 hp->dir = NULL; 213 } 214 215 if (hp->fp != NULL &&strcmp(hp->fname, pos->fname) != 0) { 216 free(hp->fname); 217 fclose(hp->fp); 218 hp->fp = NULL; 219 } 220 if (hp->fp == NULL) { 221 if ((hp->fname = strdup(pos->fname)) == NULL) 222 err(1, NULL); 223 if ((hp->fp = fopen(hp->fname, "r")) == NULL) 224 err(1, "reopen %s", hp->fname); 225 } 226 if (fseeko(hp->fp, pos->pos, SEEK_SET) == -1) 227 err(1, "seek %s", hp->fname); 228 229 if (pos->fcnt == 1) 230 /* go back to state 1 */ 231 hp->file_state = 1; 232 else 233 /* lock */ 234 hp->file_state = 3; 235} 236 237/* 238 * Rewind to position 0 239 */ 240static void 241help_file_rewind(struct help_file *hp) 242{ 243 244 if (hp->file_state == 1) { 245 if (fseeko(hp->fp, (off_t)0, SEEK_SET) == -1) 246 err(1, "rewind help file"); 247 return; 248 } 249 250 if (hp->dir != NULL) { 251 free(hp->dirname); 252 closedir(hp->dir); 253 hp->dir = NULL; 254 } 255 256 if (hp->fp != NULL) { 257 free(hp->fname); 258 fclose(hp->fp); 259 hp->fp = NULL; 260 } 261 memset(hp, 0, sizeof(*hp)); 262} 263 264/* 265 * Get next line from a help file 266 */ 267static const char * 268help_next_line(struct help_file *hp) 269{ 270 for (;;) { 271 if (hp->fp != NULL) { 272 if (fgets(hp->line, sizeof(hp->line), hp->fp) != NULL) 273 return (hp->line); 274 if (ferror(hp->fp)) 275 err(1, "%s", hp->fname); 276 free(hp->fname); 277 278 fclose(hp->fp); 279 hp->fp = NULL; 280 } 281 if (help_next_file(hp) == -1) 282 return (NULL); 283 } 284 285} 286 287/* 288 * This function prints the available 0-level help topics from all 289 * other help files by scanning the files. It assumes, that this is called 290 * only from the main help file. 291 */ 292static void 293help_get_0topics(struct help_file *hp) 294{ 295 struct help_pos save; 296 const char *line; 297 298 memset(&save, 0, sizeof(save)); 299 help_file_tell(hp, &save); 300 301 help_file_rewind(hp); 302 while ((line = help_next_line(hp)) != NULL) { 303 if (line[0] == '^' && line[1] == '^') 304 printf("%s", line + 2); 305 } 306 help_file_seek(hp, &save); 307} 308 309/* |
310 * Function to print help. The help argument is in argv[0] here. 311 */ 312static void 313help_func(int argc, char *argv[]) 314{ |
315 struct help_file hfile; 316 struct help_pos match, last_match; 317 const char *line; |
318 char key[100]; |
319 int level; 320 int i, has_sub_topics; |
321 |
322 memset(&hfile, 0, sizeof(hfile)); 323 memset(&match, 0, sizeof(match)); 324 memset(&last_match, 0, sizeof(last_match)); |
325 326 if (argc == 0) { |
327 /* only 'help' - show intro */ |
328 if ((argv[0] = strdup("intro")) == NULL) 329 err(1, NULL); 330 argc = 1; 331 } 332 333 optind = 0; |
334 match.pos = -1; 335 last_match.pos = -1; |
336 for (;;) { 337 /* read next line */ |
338 if ((line = help_next_line(&hfile)) == NULL) { |
339 /* EOF */ |
340 level = 999; 341 goto stop; 342 } |
343 if (line[0] != '^' || line[1] == '^') |
344 continue; 345 346 if (sscanf(line + 1, "%d%99s", &level, key) != 2) 347 errx(1, "error in help file '%s'", line); 348 349 if (level < optind) { 350 stop: 351 /* next higher level entry - stop this level */ |
352 if (match.pos == -1) { |
353 /* not found */ 354 goto not_found; 355 } 356 /* go back to the match */ |
357 help_file_seek(&hfile, &match); |
358 last_match = match; |
359 memset(&match, 0, sizeof(match)); 360 match.pos = -1; |
361 362 /* go to next key */ 363 if (++optind >= argc) 364 break; 365 } 366 if (level == optind) { 367 if (substr(argv[optind], key)) { |
368 if (match.pos != -1) { |
369 printf("Ambiguous topic."); 370 goto list_topics; 371 } |
372 help_file_tell(&hfile, &match); |
373 } 374 } 375 } |
376 |
377 /* before breaking above we have seeked back to the matching point */ |
378 for (;;) { |
379 if ((line = help_next_line(&hfile)) == NULL) |
380 break; |
381 |
382 if (line[0] == '#') 383 continue; |
384 if (line[0] == '^') { 385 if (line[1] == '^') 386 continue; |
387 break; |
388 } 389 if (strncmp(line, "$MAIN", 5) == 0) { 390 help_get_0topics(&hfile); 391 continue; 392 } |
393 printf("%s", line); 394 } 395 396 exit(0); 397 398 not_found: 399 printf("Topic not found."); 400 401 list_topics: |
402 printf(" Use one of:\natmconfig help"); |
403 for (i = 0; i < optind; i++) 404 printf(" %s", argv[i]); |
405 |
406 printf(" ["); |
407 |
408 /* list all the keys at this level */ |
409 if (last_match.pos == -1) 410 /* go back to start of help */ 411 help_file_rewind(&hfile); 412 else 413 help_file_seek(&hfile, &last_match); |
414 |
415 has_sub_topics = 0; 416 while ((line = help_next_line(&hfile)) != NULL) { 417 if (line[0] == '#' || line[0] != '^' || line[1] == '^') |
418 continue; 419 420 if (sscanf(line + 1, "%d%99s", &level, key) != 2) 421 errx(1, "error in help file '%s'", line); 422 423 if (level < optind) 424 break; |
425 if (level == optind) { 426 has_sub_topics = 1; |
427 printf(" %s", key); |
428 } |
429 } |
430 printf(" ]."); 431 if (!has_sub_topics) 432 printf(" No sub-topics found."); 433 printf("\n"); |
434 exit(1); 435} 436 437int 438main(int argc, char *argv[]) 439{ 440 int opt, i; 441 const struct cmdtab *match, *cc, *tab; --- 294 unchanged lines hidden --- |