Source:NetHack 3.1.0/pager.c

Below is the full text to pager.c from the source code of NetHack 3.1.0. To link to a particular line, write [[NetHack 3.1.0/pager.c#line123 ]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

1.   /*	SCCS Id: @(#)pager.c	3.1	92/09/01		  */ 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 4.     5.    /* This file contains the command routines dowhatis and dohelp and */ 6.   /* a few other help related facilities */ 7.    8.    #include	"hack.h"  9. 10.  #ifndef SEEK_SET 11.  #define SEEK_SET 0 12.  #endif 13.   14.   static boolean FDECL(is_swallow_sym, (UCHAR_P)); 15.  static int FDECL(append_str, (char *, const char *)); 16.  static void FDECL(lookat, (int, int, char *)); 17.  static void FDECL(checkfile, (char *, BOOLEAN_P)); 18.  static int FDECL(do_look, (BOOLEAN_P)); 19.  static char NDECL(help_menu); 20.  #ifdef PORT_HELP 21.  extern void NDECL(port_help); 22.  #endif 23.   24.   /* Returns "true" for characters that could represent a monster's stomach. */ 25.   static boolean 26.  is_swallow_sym(c) 27.      uchar c;  28. { 29.       int i;  30. for (i = S_sw_tl; i <= S_sw_br; i++) 31.  	if (showsyms[i] == c) return TRUE; 32.      return FALSE; 33.  }  34.    35.   /*  36.    * Append new_str to the end of buf if new_str doesn't already exist as  37. * a substring of buf. Return 1 if the string was appended, 0 otherwise. 38.   * It is expected that buf is of size BUFSZ. 39.   */  40.   static int 41.  append_str(buf, new_str) 42.      char *buf; 43.      const char *new_str; 44.  {  45.       int space_left;	/* space remaining in buf */ 46.   47.       if (strstri(buf, new_str)) return 0; 48.   49.       space_left = BUFSZ - strlen(buf) - 1; 50.      (void) strncat(buf, " or ", space_left); 51.      (void) strncat(buf, new_str, space_left - 4); 52.      return 1; 53.  }  54.    55.   /*  56.    * Return the name of the glyph found at (x,y). 57.   */  58.   static void 59.  lookat(x, y, buf) 60.      int x, y;  61. char *buf; 62.  {  63.       register struct monst *mtmp; 64.      struct trap *trap; 65.      register char *s, *t; 66.      int glyph; 67.   68.       buf[0] = 0; 69.      glyph = glyph_at(x,y); 70.      if (u.ux == x && u.uy == y && canseeself) { 71.  	Sprintf(buf, "%s called %s",  72.   #ifdef POLYSELF  73.   		u.mtimedone ? mons[u.umonnum].mname :  74.   #endif  75.   		player_mon->mname, plname); 76.      }  77.       else if (u.uswallow) { 78.  	/* all locations when swallowed other than the hero are the monster */ 79.  	Sprintf(buf, "interior of %s",  80.   				    Blind ? "a monster" : a_monnam(u.ustuck)); 81.      }  82.       else if (glyph_is_monster(glyph)) { 83.  	bhitpos.x = x;  84. bhitpos.y = y; 85. mtmp = m_at(x,y); 86.  	if(mtmp != (struct monst *) 0) { 87.  	    register boolean hp = (mtmp->data == &mons[PM_HIGH_PRIEST]); 88.   89.   	    Sprintf(buf, "%s%s%s",  90.   		    (!hp && mtmp->mtame && !Hallucination) ? "tame " :  91.   		    (!hp && mtmp->mpeaceful && !Hallucination) ?  92.   		                                          "peaceful " : "",  93.   		    (hp ? "high priest" : l_monnam(mtmp)), 94.   		    u.ustuck == mtmp ?  95.   #ifdef POLYSELF  96.   			(u.mtimedone ? ", being held" : 97.  #endif 98.  			", holding you" 99.  #ifdef POLYSELF 100. 			)  101.  #endif  102.  			: ""); 103. 	}  104.      }  105.      else if (glyph_is_object(glyph)) { 106. 	struct obj *otmp = vobj_at(x,y); 107.  108.  	if(otmp == (struct obj *) 0 || otmp->otyp != glyph_to_obj(glyph)) { 109. 	    if(glyph_to_obj(glyph) != STRANGE_OBJECT) { 110. 		otmp = mksobj(glyph_to_obj(glyph), FALSE, FALSE); 111. 		if(otmp->oclass == GOLD_CLASS) 112. 		    otmp->quan = 2L; /* to force pluralization */ 113. 		Strcpy(buf, distant_name(otmp, xname)); 114. 		dealloc_obj(otmp); 115. 	    }  116.  	} else 117. 	    Strcpy(buf, distant_name(otmp, xname)); 118.     }  119.      else if (glyph_is_trap(glyph)) { 120. 	if (trap = t_at(x, y)) { 121. 	    if (trap->ttyp == WEB) 122. 		Strcpy(buf, "web"); 123. 	    else { 124. 		Strcpy(buf, traps[ Hallucination ?  125.  				     rn2(TRAPNUM-3)+3 : trap->ttyp]); 126. 		/* strip leading garbage */ 127. 		for (s = buf; *s && *s != ' '; s++) ; 128. 		if (*s) ++s; 129. 		for (t = buf; *t++ = *s++; ) ; 130. 	    }  131.  	}  132.      }  133.      else if(!glyph_is_cmap(glyph)) 134. 	Strcpy(buf,"dark part of a room"); 135.     else switch(glyph_to_cmap(glyph)) { 136.     case S_altar: 137.         if(!In_endgame(&u.uz)) 138. 	    Sprintf(buf, "%s altar",  139.  		align_str(Amask2align(levl[x][y].altarmask & ~AM_SHRINE))); 140. 	else Sprintf(buf, "aligned altar"); 141. 	break; 142.     case S_ndoor: 143. 	if((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN) 144. 	    Strcpy(buf,"broken door"); 145. 	else 146. 	    Strcpy(buf,"doorway"); 147. 	break; 148.     default: 149. 	Strcpy(buf,defsyms[glyph_to_cmap(glyph)].explanation); 150. 	break; 151.     }  152.  }  153.   154.  /*  155.   * Look in the "data" file for more info. Called if the user typed in the 156.  * whole name (user_typed_name == TRUE), or we've found a possible match 157.  * with a character/glyph and flags.help is TRUE. 158.  *  159.   * NOTE: when (user_typed_name == FALSE), inp is considered read-only and 160.  *	 must not be changed directly, e.g. via lcase. Permitted are 161.  *	 functions, e.g. makesingular, which operate on a copy of inp. 162.  */  163.  static void 164. checkfile(inp, user_typed_name) 165.     char *inp; 166.     boolean user_typed_name; 167. {  168.      FILE *fp; 169.     char buf[BUFSZ]; 170.     char *ep; 171.     long txt_offset; 172.     boolean found_in_file = FALSE; 173.  174.      fp = fopen_datafile(DATAFILE, "r"); 175.     if (!fp) { 176. 	pline("Cannot open data file!"); 177. 	return; 178.     }  179.   180.      if (!strncmp(inp, "interior of ", 12)) 181. 	inp += 12; 182.     if (!strncmp(inp, "a ", 2)) 183. 	inp += 2; 184.     else if (!strncmp(inp, "an ", 3)) 185. 	inp += 3; 186.     else if (!strncmp(inp, "the ", 4)) 187. 	inp += 4; 188.     if (!strncmp(inp, "tame ", 5)) 189. 	inp += 5; 190.     else if (!strncmp(inp, "peaceful ", 9)) 191. 	inp += 9; 192.     if (!strncmp(inp, "invisible ", 10)) 193. 	inp += 10; 194.  195.      /* Make sure the name is non-empty. */ 196.      if (*inp) { 197. 	/* adjust the input to remove "named " and convert to lower case */ 198. 	char *alt = 0;	/* alternate description */ 199. 	if ((ep = strstri(inp, " named ")) != 0) 200. 	    alt = ep + 7; 201. 	else 202. 	    ep = strstri(inp, " called "); 203. 	if (ep) *ep = '\0'; 204. 	if (user_typed_name) 205. 	    (void) lcase(inp); 206.  207.  	/*  208.  	 * If the object is named, then the name is the alternate description; 209. 	 * otherwise, the result of makesingular applied to the name is. This 210. 	 * isn't strictly optimal, but named objects of interest to the user 211. 	 * will usually be found under their name, rather than under their 212. 	 * object type, so looking for a singular form is pointless. 213. 	 */  214.   215.  	if (!alt) 216. 	    alt = makesingular(inp); 217. 	else 218. 	    if (user_typed_name) 219. 	    	(void) lcase(alt); 220.  221.  	/* skip first record; read second */ 222. 	txt_offset = 0L; 223. 	if (!fgets(buf, BUFSZ, fp) || !fgets(buf, BUFSZ, fp)) { 224. 	    impossible("can't read 'data' file"); 225. 	    (void) fclose(fp); 226. 	    return; 227. 	} else if (sscanf(buf, "%8lx\n", &txt_offset) < 1 || txt_offset <= 0) 228. 	    goto bad_data_file; 229.  230.  	/* look for the appropriate entry */ 231. 	while (fgets(buf,BUFSZ,fp)) { 232. 	    if (*buf == '.') break;  /* we passed last entry without success */ 233.  234.  	    if (!digit(*buf)) { 235. 		if (!(ep = index(buf, '\n'))) goto bad_data_file; 236. 		*ep = 0; 237. 		if (pmatch(buf, inp) || (alt && pmatch(buf, alt))) { 238. 		    found_in_file = TRUE; 239. 		    break; 240. 		}  241.  	    }  242.  	}  243.      }  244.   245.      if(found_in_file) { 246. 	long entry_offset; 247. 	int  entry_count; 248. 	int  i;  249. 250. 	/* skip over other possible matches for the info */ 251. 	do { 252. 	    if (!fgets(buf, BUFSZ, fp)) goto bad_data_file; 253. 	} while (!digit(*buf)); 254. 	if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2) { 255. bad_data_file:	impossible("'data' file in wrong format"); 256. 		(void) fclose(fp); 257. 		return; 258. 	}  259.   260.  	if (user_typed_name || yn("More info?") == 'y') { 261. 	    winid datawin; 262.  263.  	    if (fseek(fp, txt_offset + entry_offset, SEEK_SET) < 0) { 264. 		pline("? Seek error on 'data' file!"); 265. 		(void) fclose(fp); 266. 		return; 267. 	    }  268.  	    datawin = create_nhwindow(NHW_TEXT); 269. 	    for (i = 0; i < entry_count; i++) { 270. 		if (!fgets(buf, BUFSZ, fp)) goto bad_data_file; 271. 		if ((ep = index(buf, '\n')) != 0) *ep = 0; 272. 		if (index(buf+1, '\t') != 0) (void) tabexpand(buf+1); 273. 		putstr(datawin, 0, buf+1); 274. 	    }  275.  	    display_nhwindow(datawin, FALSE); 276. 	    destroy_nhwindow(datawin); 277. 	}  278.      } else if (user_typed_name) 279. 	pline("I don't have any information on those things."); 280.  281.      (void) fclose(fp); 282. }  283.   284.  static int 285. do_look(quick) 286.     boolean quick;	/* use cursor && don't search for "more info" */ 287. {  288.      char    out_str[BUFSZ], look_buf[BUFSZ]; 289.     const char    *firstmatch = 0; 290.     int     i;  291. int    sym;		/* typed symbol or converted glyph */ 292.     int	    found;		/* count of matching syms found */ 293.     coord   cc;			/* screen pos of unknown glyph */ 294.     boolean save_verbose;	/* saved value of flags.verbose */ 295.     boolean from_screen;	/* question from the screen */ 296.     boolean need_to_look;	/* need to get explan. from glyph */ 297.     static const char *mon_interior = "the interior of a monster"; 298.  299.  #ifdef GCC_WARN 300.     sym = 0; 301. #endif 302.  303.      if (quick) { 304. 	from_screen = TRUE;	/* yes, we want to use the cursor */ 305.     } else { 306. 	i = ynq("Specify unknown object by cursor?"); 307. 	if (i == 'q') return 0; 308. 	from_screen = (i == 'y'); 309.     }  310.   311.      if (from_screen) { 312. 	cc.x = u.ux; 313. 	cc.y = u.uy; 314.     } else { 315. 	getlin("Specify what? (type the word)", out_str); 316. 	if (out_str[0] == '\033') 317. 	    return 0; 318.  319.  	if (out_str[1]) {	/* user typed in a complete string */ 320. 	    checkfile(out_str, TRUE); 321. 	    return 0; 322. 	}  323.  	sym = out_str[0]; 324.     }  325.   326.      /* Save the verbose flag, we change it later. */ 327.      save_verbose = flags.verbose; 328.     flags.verbose = flags.verbose && !quick; 329.     /*  330.       * The user typed one letter, or we're identifying from the screen. 331.      */  332.      do { 333. 	/* Reset some variables. */ 334.  	need_to_look = FALSE; 335. 	found = 0; 336. 	out_str[0] = '\0'; 337.  338.  	if (from_screen) { 339. 	    int glyph;	/* glyph at selected position */ 340.  341.  	    if (flags.verbose) 342. 		pline("Please move the cursor to an unknown object."); 343. 	    else 344. 		pline("Pick an object."); 345.  346.  	    getpos(&cc, FALSE, "an unknown object"); 347. 	    if (cc.x < 0) { 348. 		flags.verbose = save_verbose; 349. 		return 0;	/* done */ 350. 	    }  351.  	    flags.verbose = FALSE;	/* only print long question once */ 352.  353.  	    /* Convert the glyph at the selected position to a symbol. */ 354.  	    glyph = glyph_at(cc.x,cc.y); 355. 	    if (glyph_is_cmap(glyph)) { 356. 		sym = showsyms[glyph_to_cmap(glyph)]; 357. 	    } else if (glyph_is_trap(glyph)) { 358. 		sym = showsyms[(glyph_to_trap(glyph) == WEB) ? S_web : S_trap]; 359. 	    } else if (glyph_is_object(glyph)) { 360. 		sym = oc_syms[objects[glyph_to_obj(glyph)].oc_class]; 361. 	    } else if (glyph_is_monster(glyph)) { 362. 		sym = monsyms[mons[glyph_to_mon(glyph)].mlet]; 363. 	    } else if (glyph_is_swallow(glyph)) { 364. 		sym = showsyms[glyph_to_swallow(glyph)+S_sw_tl]; 365. 	    } else { 366. 		impossible("do_look:  bad glyph %d at (%d,%d)",  367.  						glyph, (int)cc.x, (int)cc.y); 368. 		sym = ' '; 369. 	    }  370.  	}  371.   372.  	/*  373.  	 * Check all the possibilities, saving all explanations in a buffer. 374. 	 * When all have been checked then the string is printed. 375. 	 */  376.   377.  	/* Check for monsters */ 378. 	for (i = 0; i < MAXMCLASSES; i++) { 379. 	    if (sym == (from_screen ? monsyms[i] : def_monsyms[i])) { 380. 		need_to_look = TRUE; 381. 		if (!found) { 382. 		    Sprintf(out_str, "%c       %s", sym, an(monexplain[i])); 383. 		    firstmatch = monexplain[i]; 384. 		    found++; 385. 		} else { 386. 		    found += append_str(out_str, an(monexplain[i])); 387. 		}  388.  	    }  389.  	}  390.   391.  	/*  392.  	 * Special case: if identifying from the screen, and we're swallowed, 393. 	 * and looking at something other than our own symbol, then just say 394. 	 * "the interior of a monster". 395. 	 */  396.  	if (u.uswallow && from_screen && is_swallow_sym((uchar) sym)) { 397. 	    if (!found) { 398. 		Sprintf(out_str, "%c       %s", sym, mon_interior); 399. 		firstmatch = mon_interior; 400. 	    } else { 401. 		found += append_str(out_str, mon_interior); 402. 	    }  403.  	    need_to_look = TRUE; 404. 	}  405.   406.  	/* Now check for objects */ 407. 	for (i = 1; i < MAXOCLASSES; i++) { 408. 	    if (sym == (from_screen ? oc_syms[i] : def_oc_syms[i])) { 409. 		need_to_look = TRUE; 410. 		if (!found) { 411. 		    Sprintf(out_str, "%c       %s", sym, an(objexplain[i])); 412. 		    firstmatch = objexplain[i]; 413. 		    found++; 414. 		} else { 415. 		    found += append_str(out_str, an(objexplain[i])); 416. 		}  417.  	    }  418.  	}  419.   420.  	/* Now check for graphics symbols */ 421. 	for (i = 0; i < MAXPCHARS; i++) { 422. 	    if (sym == (from_screen ? showsyms[i] : defsyms[i].sym) && 423.  						(*defsyms[i].explanation)) { 424. 		if (!found) { 425. 		    Sprintf(out_str, "%c       %s",  426.  					    sym, an(defsyms[i].explanation)); 427. 		    firstmatch = defsyms[i].explanation; 428. 		    found++; 429. 		} else if (!u.uswallow) { 430. 		    found += append_str(out_str, an(defsyms[i].explanation)); 431. 		}  432.   433.  		if (i == S_altar || i == S_trap || i == S_web) 434. 		    need_to_look = TRUE; 435. 	    }  436.  	}  437.   438.  	/*  439.  	 * If we are looking at the screen, follow multiple posibilities or  440. * an ambigious explanation by something more detailed. 441. 	 */  442.  	if (from_screen) { 443. 	    if (found > 1 || need_to_look) { 444. 		lookat(cc.x, cc.y, look_buf); 445. 		firstmatch = look_buf; 446. 		if (*firstmatch) { 447. 		    char temp_buf[BUFSZ]; 448. 		    Sprintf(temp_buf, " (%s)", firstmatch); 449. 		    (void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1); 450. 		    found = 1;	/* we have something to look up */ 451. 		}  452.  	    }  453.  	}  454.   455.  	/* Finally, print out our explanation. */ 456.  	if (found) { 457. 	    pline(out_str); 458. 	    /* check the data file for information about this thing */ 459. 	    if (found == 1 && !quick && flags.help) { 460. 		char temp_buf[BUFSZ]; 461. 		Strcpy(temp_buf, firstmatch); 462. 		checkfile(temp_buf, FALSE); 463. 	    }  464.  	} else { 465. 	    pline("I've never heard of such things."); 466. 	}  467.   468.      } while (from_screen && !quick); 469.  470.      flags.verbose = save_verbose; 471.     return 0; 472. }  473.   474.   475.  int 476. dowhatis 477. {  478.  	return do_look(FALSE); 479. }  480.   481.  int 482. doquickwhatis 483. {  484.  	return do_look(TRUE); 485. }  486.   487.  int 488. doidtrap 489. {  490.  	register struct trap *trap; 491. 	register int x,y; 492.  493.  	if(!getdir(NULL)) return 0; 494. 	x = u.ux + u.dx; 495. 	y = u.uy + u.dy; 496. 	for(trap = ftrap; trap; trap = trap->ntrap) 497. 		if(trap->tx == x && trap->ty == y && trap->tseen) { 498. 		    if(u.dz) { 499. 			if(u.dz < 0 && trap->ttyp == TRAPDOOR) 500. 			    continue; 501. 		        if(u.dz > 0 && trap->ttyp == ROCKTRAP) 502. 			    continue; 503. 		    }  504.  		    pline("That is a%s.",  505.  			  traps[ Hallucination ? rn1(TRAPNUM-3, 3) :  506.  				trap->ttyp]); 507. 		    return 0; 508. 		}  509.  	pline("I can't see a trap there."); 510. 	return 0; 511. }  512.   513.  int 514. dowhatdoes 515. {  516.  	FILE *fp; 517. 	char bufr[BUFSZ+6]; 518. 	register char *buf = &bufr[6], *ep, q, ctrl, meta; 519.  520.  	fp = fopen_datafile(CMDHELPFILE, "r"); 521. 	if (!fp) { 522. 		pline("Cannot open data file!"); 523. 		return 0; 524. 	}  525.   526.  #if defined(UNIX) || defined(VMS) 527. 	introff; 528. #endif 529. 	q = yn_function("What command?", NULL, '\0'); 530. #if defined(UNIX) || defined(VMS) 531. 	intron; 532. #endif 533. 	ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0); 534. 	meta = ((0x80 & q) ? (0x7f & q) : 0); 535. 	while(fgets(buf,BUFSZ,fp)) 536. 	    if ((ctrl && *buf=='^' && *(buf+1)==ctrl) ||  537.  		(meta && *buf=='M' && *(buf+1)=='-' && *(buf+2)==meta) ||  538.  		*buf==q) { 539. 		ep = index(buf, '\n'); 540. 		if(ep) *ep = 0; 541. 		if (ctrl && buf[2] == '\t'){ 542. 			buf = bufr + 1; 543. 			(void) strncpy(buf, "^?      ", 8); 544. 			buf[1] = ctrl; 545. 		} else if (meta && buf[3] == '\t'){ 546. 			buf = bufr + 2; 547. 			(void) strncpy(buf, "M-?     ", 8); 548. 			buf[2] = meta; 549. 		} else if(buf[1] == '\t'){ 550. 			buf = bufr; 551. 			buf[0] = q;  552. (void) strncpy(buf+1, "      ", 7); 553. 		}  554.  		pline("%s", buf); 555. 		(void) fclose(fp); 556. 		return 0; 557. 	    }  558.  	pline("I've never heard of such commands."); 559. 	(void) fclose(fp); 560. 	return 0; 561. }  562.   563.  /* data for help_menu */ 564. static const char *help_menu_items[] = { 565. 	"Information available:", 566. 	"",  567.  	"a.  Long description of the game and commands.", 568. 	"b.  List of game commands.", 569. 	"c.  Concise history of NetHack.", 570. 	"d.  Info on a character in the game display.", 571. 	"e.  Info on what a given key does.", 572. 	"f.  List of game options.", 573. 	"g.  Longer explanation of game options.", 574. 	"h.  List of extended commands.", 575. 	"i.  The NetHack license.", 576. #ifdef PORT_HELP 577. 	"j.  %s-specific help and commands.", 578. #endif 579. #ifdef WIZARD 580. # ifdef PORT_HELP 581. # define WIZHLP_SLOT 12	/* assumed to be next to last by code below */ 582. 	"k.  List of wizard-mode commands.", 583. # else 584. # define WIZHLP_SLOT 11	/* assumed to be next to last by code below */ 585. 	"j.  List of wizard-mode commands.", 586. # endif 587. #endif 588. 	"",  589.  	NULL 590. };  591.   592.  static char 593. help_menu 594. {  595.  	winid tmpwin = create_nhwindow(NHW_MENU); 596. #ifdef PORT_HELP 597. 	char helpbuf[QBUFSZ]; 598. #endif 599. 	char hc; 600. 	register int i;  601. 602. 	start_menu(tmpwin); 603. #ifdef WIZARD 604. 	if (!wizard) help_menu_items[WIZHLP_SLOT] = "", 605. 		     help_menu_items[WIZHLP_SLOT+1] = NULL; 606. #endif 607. 	for (i = 0; help_menu_items[i]; i++) 608. #ifdef PORT_HELP 609. 	    /* port-specific line has a %s in it for the PORT_ID */ 610. 	    if (index(help_menu_items[i], '%')) { 611. 		Sprintf(helpbuf, help_menu_items[i], PORT_ID); 612. 		add_menu(tmpwin, helpbuf[0], 0, helpbuf); 613. 	    } else 614. #endif 615. 	    {  616.  		add_menu(tmpwin, i ? *help_menu_items[i] : 0, 0,  617.  			 help_menu_items[i]); 618. 	    }  619.  	end_menu(tmpwin, '\033', "\033", "Select one item or ESC: "); 620. 	hc = select_menu(tmpwin); 621. 	destroy_nhwindow(tmpwin); 622. 	return hc; 623. }  624.   625.  int 626. dohelp 627. {  628.  	char hc = help_menu; 629. 	if (!index(quitchars, hc)) { 630. 		switch(hc) { 631. 			case 'a':  display_file(HELP, TRUE);  break; 632. 			case 'b':  display_file(SHELP, TRUE);  break; 633. 			case 'c':  (void) dohistory;  break; 634. 			case 'd':  (void) dowhatis;  break; 635. 			case 'e':  (void) dowhatdoes;  break; 636. 			case 'f':  option_help;  break; 637. 			case 'g':  display_file(OPTIONFILE, TRUE);  break; 638. 			case 'h':  (void) doextlist;  break; 639. 			case 'i':  display_file(LICENSE, TRUE);  break; 640. #ifdef PORT_HELP 641. 			case 'j':  port_help;  break; 642. # ifdef WIZARD 643. 			case 'k':  display_file(DEBUGHELP, TRUE);  break; 644. # endif 645. #else 646. # ifdef WIZARD 647. 			case 'j':  display_file(DEBUGHELP, TRUE);  break; 648. # endif 649. #endif 650. 		}  651.  	}  652.  	return 0; 653. }  654.   655.  int 656. dohistory 657. {  658.  	display_file(HISTORY, TRUE); 659. 	return 0; 660. }  661.   662.  /*pager.c*/