Annotation of libwww/LineMode/src/HTBrowse.c, revision 1.44

1.44    ! frystyk     1: /*                                                                  HTBrowse.c
        !             2: **     HYPERTEXT BROWSER FOR DUMB TERMINALS
        !             3: **
        !             4: **     (c) COPYRIGHT CERN 1994.
        !             5: **     Please first read the full copyright statement in the file COPYRIGH.
1.1       timbl       6: **
                      7: **  Authors:
                      8: **     NP:  Nicola Pellow  Tech.Student CERN 1990-91
                      9: **     TBL: Tim Berners-Lee CERN (timbl@info.cern.ch)
                     10: **     JFG: Jean-Francois Groff, Cooperant CERN 1991-92 (jfg@info.cern.ch)
                     11: **     DR:  Dudu Rashty +972-2-584848 <RASHTY@hujivms.bitnet>
1.8       duns       12: **     MD:  Mark Donszelmann, DELPHI CERN, (duns@vxdeop.cern.ch)
1.34      frystyk    13: **     HFN: Henrik Frystyk Nielsen, CERN, (frystyk@dxcern.cern.ch)
1.1       timbl      14: **
                     15: **  History:
                     16: **
                     17: **   4 Dec 90:  Written from scratch (NP)
                     18: **  11 Feb 91:  Code written by TBL so that the browser could be linked with
                     19: **              code produced by Bernd Pollermann, enabling access to the
                     20: **              data on CERNVM. This involved changing the code to handle file
                     21: **              numbers rather than file pointers.
                     22: **  18 Mar 91:  The feature of history mechanism was included, enabling a  
                     23: **              record of previous nodes visited to be kept.
                     24: **   6 Apr 91:  When a node is accessed, it is immediately read into a 
1.40      frystyk    25: **              buffer, in an unformatted state, as soon as the connection is  
1.1       timbl      26: **              made, so that the server is freed as quickly as possible. 
                     27: **              The program now also uses the additional modules HTBufferFile.c
                     28: **              and HTBufferFile.h.
                     29: **  17 Apr 91:  Can be used on machines running ANSI C and ordinary C.
                     30: **  10 May 91:  Formatted text is stored in a linked list buffer which allows
                     31: **              scrolling and better page breaks in the middle of text.
                     32: **              Code incorporated by Tim BL, to enable anonymous FTP.          
                     33: **  21 May 91:  Accepts various parameters on the command line.
                     34: **  19 Aug 91:  Currently available in Unix, VAX/VMS and MVS environments.
                     35: **  21 Nov 91:  Character grid uses new architecture. (TBL)
                     36: **              added -w option, new commands, print,
                     37: **                  ...        See Features.html for further details
                     38: **  16 Jan 92:  Put in VIOLA-compatible options - see \017 characters.
                     39: **                  \017 and \016 bracket user-selectable input.
                     40: **  27 Feb 92: New handling of user input, enhanced command syntax. (JFG)
                     41: **  18 May 92: PS command see ifdef SLAVE_PRINTER (DR/TBL)
                     42: **   6 Oct 92:  Painful recovery from someone(?)'s attept to pretty print.(TBL)
                     43: **             Please see coding style guide before changing indentation etc!
                     44: **     Mar 93: Force on HTFile's HTDirAccess and HTDirReadme flags.
1.8       duns       45: **   3 Nov 93: (MD) Changed vms into VMS
                     46: **             (MD) Assigne output in main, not at initialize (VMS only)
1.1       timbl      47: **
                     48: ** Compilation-time macro options
                     49: **
                     50: **     REF_MARK        Printf string to be used for printing anchor numbers
                     51: **     END_MARK        String to be used to denote the end of a document
                     52: **     VL              Version number, quoted eg "1.2a"
                     53: */
                     54: 
                     55: #include <ctype.h>
1.11      frystyk    56: #include "HTUtils.h"   /* WWW general purpose macros */
                     57: #include "HTBrowse.h"  /* Things exported, short names */
                     58: #include "GridText.h"  /* Hypertext definition */
1.1       timbl      59: 
                     60: #include "HTFormat.h"
                     61: #include "HTTCP.h"     /* TCP/IP utilities */
                     62: #include "HTAnchor.h"   /* Anchor class */
                     63: #include "HTParse.h"    /* WWW address manipulation */
                     64: #include "HTAccess.h"   /* WWW document access network code */
                     65: #include "HTHistory.h" /* Navigational aids */
                     66: #include "HTML.h"      /* For parser */
                     67: #include "HTFWriter.h" /* For non-interactive output */
1.33      timbl      68: #include "HTMLGen.h"   /* For reformatting HTML */
1.1       timbl      69: #include "HTFile.h"    /* For Dir access flags */
1.3       timbl      70: #include "HTRules.h"    /* For loading rule file */
1.30      frystyk    71: #include "HTError.h"
1.38      frystyk    72: #include "HTAlert.h"
1.41      frystyk    73: #include "HTTP.h"
1.40      frystyk    74: #include "HTEvent.h"
                     75: 
                     76: /* HWL 18/7/94: applied patch from agl@glas2.glas.apc.org (Anton Tropashko) */
                     77: #ifdef CYRILLIC                
                     78: #include "a_stdio.h"
                     79: #endif
1.1       timbl      80: 
1.40      frystyk    81: #ifdef THINK_C                      /* Macintosh Think C development system */
1.1       timbl      82: #include <console.h>
                     83: #include <time.h>
1.40      frystyk    84: extern int socketdebug;                   /* Must be declared in the socket library */
                     85: #endif
                     86: 
                     87: /* Macros and other defines */
                     88: #ifndef VL
                     89: #define VL "unspecified"
                     90: #endif
                     91: 
                     92: /*     If the guy gives the "MANUAL" command, jump to this: */
                     93: #ifndef MANUAL
                     94: #define MANUAL "http://info.cern.ch/hypertext/WWW/LineMode/Defaults/QuickGuide.html"
                     95: #endif
                     96: 
                     97: #ifndef COM_HELP_FILE
                     98: #define COM_HELP_FILE "http://info.cern.ch/hypertext/WWW/LineMode/Defaults/CommandLine.html"
1.1       timbl      99: #endif
                    100: 
1.40      frystyk   101: #ifndef DEFAULT_LOCAL_LOGFILE
                    102: #define DEFAULT_LOCAL_LOGFILE          "WWW-log"       /* Log file name for local execution */
                    103: #endif
1.1       timbl     104: 
1.40      frystyk   105: #ifndef DEFAULT_OUTPUT_FILE
                    106: #define DEFAULT_OUTPUT_FILE            "WWW-out"       /* Output file name for non-interactive run */
1.37      howcome   107: #endif
                    108: 
1.40      frystyk   109: #ifndef DEFAULT_REF_HEAD
                    110: #define DEFAULT_REF_HEAD               "*** References from this document ***"
                    111: #endif
1.1       timbl     112: 
                    113: #ifndef REF_MARK               /* May be redefined on command line */
                    114: #ifdef VIOLA
                    115: #define REF_MARK "[\017%d\016]"        /* Shift-in, shift-out around number */
                    116: #define PROMPT_MARK "\017%s\016"
                    117: #else
                    118: #define PROMPT_MARK "%s"
                    119: #ifdef VM
                    120: #define REF_MARK " <%d>"       /* IBM terminals can't handle [] well */
                    121: #else
                    122: #define REF_MARK "[%d]"
                    123: #endif
                    124: #endif
                    125: #endif
                    126: 
                    127: #ifndef END_MARK
                    128: #ifdef VM
                    129: #define END_MARK "     <End>"
                    130: #else
                    131: #define END_MARK "     [End]"
                    132: #endif
                    133: #endif
                    134: 
                    135: #ifdef NEWLIB
1.13      frystyk   136: #define SCREEN_WIDTH           78
1.1       timbl     137: #endif
                    138: 
                    139: #ifndef SCREEN_WIDTH      
1.13      frystyk   140: #define SCREEN_WIDTH           79  /* Default width of the screen */ 
1.1       timbl     141: #endif
1.13      frystyk   142: 
                    143: #ifndef MIN_SCREEN_WIDTH
                    144: #define MIN_SCREEN_WIDTH       10 
                    145: #endif
                    146: 
                    147: #ifndef MAX_SCREEN_WIDTH
                    148: #define MAX_SCREEN_WIDTH       150      
                    149: #endif
                    150: 
1.1       timbl     151: #ifndef SCREEN_HEIGHT
1.13      frystyk   152: #define SCREEN_HEIGHT          24 /* Default number of lines to the screen */
                    153: #endif
                    154: 
                    155: #ifndef MIN_SCREEN_HEIGHT
                    156: #define MIN_SCREEN_HEIGHT      5 
                    157: #endif
                    158: 
                    159: #ifndef MAX_SCREEN_HEIGHT
1.14      frystyk   160: #define MAX_SCREEN_HEIGHT      200      
1.1       timbl     161: #endif
                    162: 
1.16      frystyk   163: #define INFINITY               1024                                 /*!! BUG*/
                    164: #define ADDRESS_LENGTH         INFINITY   /* Maximum address length of node */
                    165: #define RESPONSE_LENGTH                INFINITY /* Maximum length of users response */
                    166: 
                    167: #ifndef MAXPATHLEN
                    168: #define NO_GETWD                      /* Assume no  getwd() if no MAXPATHLEN */
                    169: #endif
1.1       timbl     170: 
1.40      frystyk   171: /* #define LONG_PROMPT 1 */                    /* Long or short user prompt */
                    172: 
                    173: #if defined(ultrix) || defined(__osf__)
                    174: #define GET_SCREEN_SIZE
                    175: #endif
                    176: 
                    177: #define Check_User_Input(command) \
                    178:     (!strncasecomp (command, this_word, strlen(this_word)))
1.1       timbl     179: 
1.40      frystyk   180: /* Public Variables etc. */
                    181: /* HWL 18/7/94: applied patch from agl@glas2.glas.apc.org (Anton Tropashko) */
                    182: #ifdef CYRILLIC
                    183: struct ARc arc;
                    184: #endif
1.2       timbl     185: 
1.40      frystyk   186: PUBLIC char *          HTAppName = "CERN-LineMode";     /* Application name */
                    187: PUBLIC char *          HTAppVersion = VL;            /* Application version */
                    188: PUBLIC int             HTScreenWidth   = SCREEN_WIDTH;        /* By default */
                    189: PUBLIC int             HTScreenHeight  = -1;              /* -1 = Undefined */
                    190: PUBLIC BOOL            display_anchors = YES;      /* Show anchors in text? */
                    191: PUBLIC char *          start_reference = NULL;   /* Format for start anchor */
                    192: PUBLIC char *          end_reference = REF_MARK;          /* for end anchor */
                    193: PUBLIC char *          reference_mark = "[%d] ";     /* for reference lists */
                    194: PUBLIC char *          end_mark = END_MARK;      /* Format string for [End] */
1.1       timbl     195:  
1.40      frystyk   196: /* Type definitions and global variables local to this module */
                    197: PRIVATE HTRequest *    request = NULL;
                    198: PRIVATE        HTList *        reqlist = NULL;           /* List of active requests */
                    199: PRIVATE HTParentAnchor*        home_anchor = NULL;         /* First document anchor */
                    200: PRIVATE char           keywords[ADDRESS_LENGTH];       /* From command line */
                    201: PRIVATE char *         output_file_name = NULL;                  /* -o xxxx */
                    202: PRIVATE char           choice[RESPONSE_LENGTH];          /* Users response  */
                    203: PRIVATE char *         refhead = DEFAULT_REF_HEAD;      /* Ref list heading */
                    204: PRIVATE char *         logfile_root = NULL;                /* Log file name */
                    205: PRIVATE BOOL           filter = NO;                     /* Load from stdin? */
                    206: PRIVATE BOOL           reformat_html = NO;                /* Reformat html? */
                    207: PRIVATE BOOL           listrefs_option = NO;     /* -listrefs option used?  */
                    208: PRIVATE BOOL           OutSource = NO;             /* Output source, YES/NO */
                    209: PRIVATE char *         HTLogFileName = NULL;       /* Root of log file name */
                    210: PRIVATE int            OldTraceFlag = SHOW_ALL_TRACE;
1.8       duns      211: 
                    212: #ifdef VMS
                    213: PRIVATE FILE *       output;           /* assignment done in main */
1.17      duns      214: #ifdef __DECC
                    215: /* dummy declarations to make sure that LINKER will not complain */
                    216: PUBLIC char *HTBinDir;
                    217: PUBLIC int HTDiag;
                    218: PUBLIC char *HTPostScript;
                    219: PUBLIC char *HTPutScript;
                    220: PUBLIC char *HTSearchScript;
                    221: #endif /* DECC */
1.8       duns      222: #else /* not VMS */
1.4       timbl     223: PRIVATE FILE *      output = stdout;
1.8       duns      224: #endif /* not VMS */ 
1.4       timbl     225: 
1.40      frystyk   226: /* ------------------------------------------------------------------------- */
                    227: /*                             HELP FUNCTIONS                               */
                    228: /* ------------------------------------------------------------------------- */
1.7       secret    229: 
                    230: #ifdef GET_SCREEN_SIZE
                    231: #include <sys/ioctl.h>
                    232: /*
1.40      frystyk   233: ** Get size of the output screen. Stolen from less.
                    234: */
                    235: PRIVATE void scrsize ARGS2(int *, p_height, int *, p_width)
1.7       secret    236: {
                    237:       register char *s;
                    238:       int ioctl();
                    239:       struct winsize w;
                    240: 
                    241:       if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_row > 0)
                    242:               *p_height = w.ws_row;
                    243:       else
                    244:       if ((s = getenv("LINES")) != NULL)
                    245:               *p_height = atoi(s);
                    246:       else
                    247:               *p_height = SCREEN_HEIGHT;
                    248: 
                    249:       if (ioctl(2, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)
                    250:               *p_width = w.ws_col;
                    251:       else
                    252:       if ((s = getenv("COLUMNS")) != NULL)
                    253:               *p_width = atoi(s);
                    254:       else
                    255:               *p_width = 80;
                    256: }
                    257: #endif /* GET_SCREEN_SIZE, BSN */
                    258: 
                    259: 
1.40      frystyk   260: /*             Display Help screen                      Help_screen
                    261: **             -------------------
                    262: ** Produce a help screen, displaying the current document address and
                    263: ** a list of * available commands *in this context*.  * ?? Perhaps this
                    264: ** should be a hypertext page, not included in the history list.
1.1       timbl     265: */
1.40      frystyk   266: PRIVATE void help_screen NOARGS {
                    267: 
                    268:     char * current_address = HTAnchor_address((HTAnchor*)HTMainAnchor);
                    269:     CONST char * title = HTAnchor_title(HTMainAnchor);
                    270:     
                    271:     printf("\n\nWWW LineMode Browser version %s (WWWLib %s)   COMMANDS AVAILABLE\n\n",
                    272:                            VL, HTLibraryVersion);
                    273:     if (title) printf("You are reading\n \"%s\"\nwhose address is\n  %s\n\n",
                    274:                                                    title, current_address);
                    275:     else printf("You are reading a document whose address is\n    '%s' \n\n",
                    276:                                    current_address);
                    277:     
                    278:     if (HText_canScrollDown(HTMainText)) {
                    279:        printf(
                    280:                "  <RETURN>        Move down one page within the document.\n");
                    281:        printf(
                    282:                "  BOttom          Go to the last page of the document.\n");
                    283:        };
                    284:            
                    285:     if (HText_canScrollUp(HTMainText)) {
                    286:        printf(
                    287:                "  Top             Return to the first page of the document.\n");
                    288:        printf(
                    289:                "  Up              Move up one page within the document\n");
                    290:        };
                    291:            
                    292:     if (HText_sourceAnchors(HTMainText) != 0) {
                    293:        printf("  List            List the references from this document.\n *");
                    294:        printf("  <number>        Select a referenced document by number (from 1 to %d).\n",
                    295:                HText_sourceAnchors(HTMainText));
                    296:     }
                    297:            
                    298:     if (HTAnchor_isIndex(HTMainAnchor)) {
                    299:        printf(
                    300:                "  Find <words>    Search this index for given words (separated by spaces).\n"); 
                    301:     }
                    302:            
                    303:     if (HTHistory_canBacktrack()) {
                    304:        printf("  Recall          List visited documents.\n");
                    305:        printf("  Recall <number> Return to a previously visited document\n");
                    306:        printf("                  as numbered in the recall list.\n");
                    307:        printf("  HOme            Return to the starting document.\n");
                    308:        printf("  Back            Move back to the last document.\n");
                    309:     }
                    310:            
                    311:     if (HTHistory_canMoveBy(1))
                    312:            printf("  Next            Take next link from last document.\n");
                    313:                    
                    314:     if (HTHistory_canMoveBy(-1))
                    315:            printf("  Previous        Take previous link from last document.\n");
1.1       timbl     316: 
1.40      frystyk   317:     printf("  REFresh         Refresh screen with current document\n");
                    318:     printf("  Go <address>    Go to document of given [relative] address\n");
                    319:            
                    320: #ifdef GOT_SYSTEM
                    321:     if (!HTClientHost) {       /* NOT for telnet guest! */
                    322:            printf("  PRInt           Print text of this document. *\n");
                    323:            printf("  ! <command>     Execute shell <command> without leaving.\n");
                    324:            printf("  > <file>        Save the text of this document in <file>. *\n");
                    325:            printf("                  If <file> exists use '>!' to overwrite it.\n");
                    326:            printf("  >> <file>       Append the text of this document to <file>. *\n");
                    327:            printf("  | <command>     Pipe this document to the shell <command>. *\n");
                    328: #ifdef unix
                    329:            printf("  CD <directory>  Change local working directory.\n");
                    330: #endif
                    331:            printf("* Prefix these commands with \"Source \" to use raw source.\n\n");
                    332:     }
                    333: #endif
                    334:            
                    335: #ifdef SLAVE_PRINTER
                    336:     printf(
                    337:     "  Ps              Print text of this document to Terminal's Slave printer.\n");
1.1       timbl     338: #endif
1.40      frystyk   339:            
                    340:     printf("  Verbose         Switch to %sverbose mode.\n", WWW_TraceFlag ? "non-" : "");
                    341:            
                    342:     printf("  Help            Display this page.\n");
                    343:     printf("  Manual          Jump to the online manual for this program\n");
                    344:     printf("  Quit            Leave the www program.\n");          
                    345:     printf("\n");
                    346:     free(current_address);    
                    347: } /* End of help_screen */
1.1       timbl     348: 
                    349: 
1.40      frystyk   350: #ifdef OLD_CODE
                    351: /*             Select_Reference
                    352: **             ----------------
                    353: **
                    354: **  After a reference is selected by the user, opens document, links into the
                    355: **  history list and displays.
                    356: **
                    357: **  On Entry:
                    358: **       int  reference_num   Number corresponding to the hypertext reference
                    359: **                            given in the text.
                    360: */
1.7       secret    361: 
1.40      frystyk   362: BOOL Select_Reference ARGS1(int,reference_num) {
                    363:  
                    364:     HTAnchor           * destination;
                    365:     HTChildAnchor * source = HText_childNumber(HTMainText, reference_num);
                    366:     
                    367:     if (!source) return NO; /* No anchor */
                    368:     destination = HTAnchor_followMainLink((HTAnchor*) source);
                    369:     request->parentAnchor = HTAnchor_parent((HTAnchor *) source);
                    370:     if (!HTLoadAnchor(destination, request)) return NO;        /* No link */
                    371:     HTHistory_leavingFrom((HTAnchor*) source);
                    372:     HTHistory_record(destination);
                    373:     request->parentAnchor = NULL;
                    374:     return YES;
1.37      howcome   375:     
1.40      frystyk   376: } /* Select_Reference*/
1.37      howcome   377: #endif
1.8       duns      378: 
1.40      frystyk   379: /*     Reference_List
                    380: **     --------------
                    381: **     Print out a list of HyperText References accumulated within the text.
                    382: **
                    383: ** On entry
                    384: **     titles          Set:    if we want titles where available
                    385: **                     Clear:  we only get addresses.
                    386: */
1.7       secret    387: 
1.40      frystyk   388: PRIVATE void Reference_List ARGS1(BOOL, titles)
1.1       timbl     389: 
1.40      frystyk   390: {
                    391:     int  n;
                    392:     if (HText_sourceAnchors(HTMainText) == 0) {
                    393:        fprintf(output, "\n\nThere are no references from this document.\n\n");
                    394:     } else {
                    395:        fprintf(output, "\n%s\n", refhead);
                    396:        for (n=1; n<=HText_sourceAnchors(HTMainText); n++) {
                    397:            HTAnchor * destination =
                    398:            HTAnchor_followMainLink(
                    399:                    (HTAnchor *)HText_childNumber(HTMainText, n)
                    400:                    );
                    401:            HTParentAnchor * parent = HTAnchor_parent(destination);
                    402:            char * address =  HTAnchor_address(destination);
                    403:            CONST char * title = titles ? HTAnchor_title(parent) : 0 ;
1.1       timbl     404: 
1.40      frystyk   405:            fprintf(output, reference_mark, n);
                    406:            fprintf(output, "%s%s\n",
                    407:                    ((HTAnchor*)parent!=destination) && title ? "in " : "",
                    408:                    (char *)(title ? title : address));
                    409:            free(address);
                    410:        }
                    411:        fflush(stdout);
                    412:     }
                    413: }      
1.1       timbl     414: 
                    415: 
1.40      frystyk   416: /*             History_List
                    417: **             ------------
                    418: */
                    419: /*     Display a history list of nodes visited during the session.
                    420: **     ?? This should really be a hypertext page (not itself in history!).
                    421: **     ?? Should have option to display address even when anchor has a title.
1.1       timbl     422: */
                    423: 
1.40      frystyk   424: PRIVATE void History_List NOARGS {
1.38      frystyk   425: 
1.40      frystyk   426:     int  history_number = 1; 
                    427:     printf("\n  Documents you have visited:-\n\n");
1.1       timbl     428:     
1.40      frystyk   429:     do {
1.1       timbl     430:     
1.40      frystyk   431:        char * address;
                    432:        CONST char * title;
                    433:        HTAnchor * anchor = HTHistory_read(history_number);
                    434:        HTParentAnchor * parent;
1.1       timbl     435:        
1.40      frystyk   436:        if (!anchor) break;
                    437:        parent = HTAnchor_parent(anchor);
                    438:        title = HTAnchor_title(parent);
                    439:        address = HTAnchor_address(anchor);
                    440: #ifdef VIOLA
                    441:        printf("\017R %2d\016)   %s%s\n",       /* SI user field SO */
1.1       timbl     442: #else
1.40      frystyk   443:        printf("R %2d)   %s%s\n",
1.1       timbl     444: #endif
1.40      frystyk   445:                history_number,
                    446:                ((HTAnchor*)parent!=anchor) && title ? "in " : "",
                    447:                title ? title : address);
                    448:        free(address);
                    449:        
                    450:        history_number++;
                    451:        
                    452:     } while (YES);
1.1       timbl     453: 
1.40      frystyk   454:     printf("\n");
1.1       timbl     455: }
                    456: 
                    457: 
1.40      frystyk   458: /*                                                             MakeCommandLine
1.1       timbl     459: **
1.40      frystyk   460: **     Generate the Prompt line and flush it to the user
1.1       timbl     461: */
1.40      frystyk   462: PRIVATE void MakeCommandLine ARGS1(BOOL, is_index)
                    463: {
                    464:     int length_of_prompt = 0;
1.1       timbl     465: 
1.40      frystyk   466: #ifndef VM     /* Normal prompt */
                    467:     if (is_index){     
                    468:        printf("FIND <keywords>, ");
                    469:        length_of_prompt = length_of_prompt + 14;
                    470:     }
                    471:     if (HTAnchor_hasChildren(HTMainAnchor)!=0){
                    472:        int refs = HText_sourceAnchors(HTMainText);
                    473:        if (refs>1) {
                    474:            printf("1-%d, ", refs);
                    475:            length_of_prompt = length_of_prompt + 6;              /* Roughly */
                    476:        }
                    477:        else {
                    478:            printf("1, ");      
                    479:            length_of_prompt = length_of_prompt + 3;
                    480:        }
                    481:     }
                    482:     if (HTHistory_canBacktrack()){
                    483:        printf(PROMPT_MARK, "Back"); printf(", ");
                    484: #ifdef LONG_PROMPT
                    485:        printf(PROMPT_MARK, "Recall"); printf(", ");
                    486: #endif
                    487:        length_of_prompt = length_of_prompt + 6;
                    488:     }
                    489:     if (HText_canScrollUp(HTMainText)){ 
                    490:        printf(PROMPT_MARK,"Up"); printf(", ");
                    491:        length_of_prompt = length_of_prompt + 4;
                    492:     }
                    493:     if (HText_canScrollDown(HTMainText)) {
                    494:        printf("<RETURN> for more, ");
                    495:        length_of_prompt = length_of_prompt + 19;
                    496:     }
                    497:     if (length_of_prompt <= 47) {
                    498:        printf(PROMPT_MARK, "Quit"); printf(", ");
                    499:     }
1.1       timbl     500:     
1.40      frystyk   501:     printf("or Help: ");       
                    502:        
                    503: #else  /* Special prompt for VM assuming PF keys set*/
                    504:     if (is_index) {    
                    505:        printf("FIND <words>, ");                                      /* 14 */
                    506:        length_of_prompt = length_of_prompt + 14;
                    507:     }
                    508:     if (HTAnchor_hasChildren(HTMainAnchor)!=0){
                    509:        int refs = HText_sourceAnchors(HTMainText);
                    510:        if (refs>1) {
                    511:            printf("1-%d, ", refs);
                    512:            length_of_prompt = length_of_prompt + 6;             /* approx 6 */
                    513:        }
                    514:        else {
                    515:            printf("1, ");
                    516:            length_of_prompt = length_of_prompt + 3;
                    517:        }
                    518:     }
                    519:     if (HTHistory_canMoveBy(1)) {
                    520:        printf("PF2=Next ");
                    521:        length_of_prompt = length_of_prompt + 9;                        /* 9 */
                    522:     }
                    523:     printf("PF3=Quit PF4=Return, ");
                    524:     length_of_prompt = length_of_prompt + 21;                          /* 21 */
1.1       timbl     525:     
1.40      frystyk   526:     if (HTHistory_canBacktrack()){
                    527:        printf("Recall, ");
                    528:        length_of_prompt = length_of_prompt + 8;                        /* 8 */
1.1       timbl     529:     }
1.40      frystyk   530:     if (HText_canScrollUp(HTMainText)){
                    531:        printf(PROMPT_MARK,"PF7=Up "); printf(", ");
                    532:        length_of_prompt = length_of_prompt + 7;                        /* 7 */
1.1       timbl     533:     }
1.40      frystyk   534:     if (HText_canScrollDown(HTMainText)){
                    535:        printf("PF8=Down ");
                    536:        length_of_prompt = length_of_prompt + 9;                        /* 9 */
1.1       timbl     537:     }
1.40      frystyk   538:     if (length_of_prompt<70) printf("PF11=Help");                      /* 9 */
                    539:                                                                  /* EQUAL 82 */
1.1       timbl     540: #endif
                    541: 
1.44    ! frystyk   542:     fflush(stdout);                      /* For use to flush out the prompt */
1.40      frystyk   543:     return;
                    544: }
1.1       timbl     545: 
1.40      frystyk   546: /*                                                                      ErrMsg
                    547: **
                    548: **   General Error Message for Line Mode Browser. If verbose mode is on, then
                    549: **   the message is passed to stderr.
                    550: **
                    551: */
                    552: PRIVATE void ErrMsg ARGS2(char *, Msg, char *, Str)
                    553: {
1.44    ! frystyk   554:     if (TRACE || HTInteractive)
        !           555:        fprintf(stderr, "Warning: %s (%s)\n", Msg, Str ? Str : "");
1.40      frystyk   556: }
1.1       timbl     557: 
1.40      frystyk   558: /* ------------------------------------------------------------------------- */
                    559: /*                             EVENT FUNCTIONS                              */
                    560: /* ------------------------------------------------------------------------- */
1.1       timbl     561: 
1.40      frystyk   562: /*
                    563: **  This function creates a new request structure and adds it to the global
                    564: **  list of active threads
1.1       timbl     565: */
1.40      frystyk   566: PRIVATE HTRequest *Thread_new ARGS1(BOOL, Interactive)
                    567: {
                    568:     HTRequest *newreq = HTRequest_new();            /* Set up a new request */
                    569:     if (!reqlist)
                    570:        reqlist = HTList_new();
                    571:     HTList_addObject(reqlist, (void *) newreq);
                    572:     if (Interactive)
                    573:        HTFormatInit(newreq->conversions);
                    574:     else
                    575:        HTFormatInitNIM(newreq->conversions);
                    576:     return newreq;
                    577: }
1.1       timbl     578: 
                    579: 
1.40      frystyk   580: /*
                    581: **  This function deletes a request structure and takes it out of the list
                    582: **  of active threads.
                    583: */
                    584: PRIVATE void Thread_delete ARGS1(HTRequest *, oldreq)
                    585: {
                    586:     if (oldreq) {
                    587:        if (reqlist)
                    588:            HTList_removeObject(reqlist, (void *) oldreq);
                    589:        HTRequest_delete(oldreq);
                    590:     }
                    591: }
1.1       timbl     592: 
1.40      frystyk   593: /*
                    594: **  This function deletes the whole list of active threads.
                    595: */
                    596: PRIVATE void Thread_deleteAll NOARGS
                    597: {
                    598:     if (reqlist) {
                    599:        HTList *cur = reqlist;
                    600:        HTRequest* pres;
                    601:        while ((pres = (HTRequest *) HTList_nextObject(cur)) != NULL)
                    602:            HTRequest_delete(pres);
                    603:        HTList_delete(reqlist);
                    604:        reqlist = NULL;
                    605:     }
                    606: }
1.1       timbl     607: 
                    608: 
                    609: /*
1.40      frystyk   610: **  This function puts up a stream to a file in order to save a document. This
                    611: **  is activated by '>', '>>' or '>!' from the prompt line.
                    612: **  Returns NO if Error and YES if OK
1.1       timbl     613: **
1.40      frystyk   614: **  Henrik Frystyk 02/03-94
1.1       timbl     615: */
1.40      frystyk   616: PRIVATE BOOL SaveOutputStream ARGS2(char *, This, char *, Next)
                    617: {
                    618:     FILE *fp;
                    619:     char *fname;
                    620:     char *fmode;
                    621:     
                    622:     /* Checks if file exists. Can be overruled by using '>!' */
                    623:     if (*(This+1) == '>') {                               /* Append to file */
                    624:        fmode = "a";
                    625:        fname = *(This+2) ? (This+2) : Next;
                    626:     } else if (*(This+1) == '!') {
                    627:        fmode = "w";                                       /* Overwrite file */
                    628:        fname = *(This+2) ? (This+2) : Next;
                    629:     } else {                                           /* File name follows */
                    630:        fmode = "w";
                    631:        fname = *(This+1) ? (This+1) : Next;
                    632:        if (fname) {                                   /* See if file exists */
                    633:            if ((fp = fopen(fname, "r")) != NULL) {
                    634:                printf("%s: File exists\n", fname);
                    635:                fclose(fp);
                    636:                return NO;
                    637:            }
                    638:        }
                    639:     }
                    640:     if (!fname)                                               /* No file name given */
                    641:        return NO;
                    642:     if ((fp = fopen(fname, fmode)) == NULL) {
                    643:        ErrMsg("Can't access file", fname);
                    644:        return NO;
                    645:     }
1.1       timbl     646: 
1.40      frystyk   647:     /* Now, file is open and OK: reload the text and put up a stream for it! */
                    648:     if (TRACE) fprintf(stderr, "Saving to file %s\n", fname);
                    649:     {
                    650:        BOOL ret = NO;
                    651:        HTRequest *req = Thread_new(NO);             /* Set up a new request */
                    652:        if(OutSource)
                    653:            req->output_format = WWW_SOURCE;
                    654:        req->output_stream = HTFWriter_new(fp, NO);
                    655:        HTForceReload = YES;
                    656:        ret = HTLoadAnchor((HTAnchor*) HTMainAnchor, req);
                    657:        HTForceReload = NO;
                    658:        return ret;
                    659:     }
                    660: }
1.1       timbl     661: 
                    662: 
1.40      frystyk   663: /*                                                                EventHandler
                    664: **
                    665: **     Read in the user's input, and deal with it as necessary.
                    666: **
                    667: **     Any Command which works returns from the routine. If nothing
                    668: **     works then a search or error message down at the bottom.
1.1       timbl     669: */
1.40      frystyk   670: PUBLIC HTEventState EventHandler ARGS1(HTRequest *, actreq)
1.1       timbl     671: { 
1.40      frystyk   672:     int  ref_num;
1.44    ! frystyk   673:     int  status = EVENT_OK;
1.40      frystyk   674:     char * the_choice = 0;                        /* preserved user command */
                    675:     char * this_word = 0;                          /* First word of command */
                    676:     char * this_command;                         /* this_word and following */
                    677:     char * next_word;                                        /* Second word */
                    678:     char * other_words;                                /* Second word and following */
1.14      frystyk   679:     BOOL is_index = HTAnchor_isIndex(HTMainAnchor);
1.40      frystyk   680: 
                    681:     if (!fgets(choice, RESPONSE_LENGTH, stdin))                  /* Read User Input */
                    682:        return EVENT_QUIT;                                    /* Exit if EOF */
                    683:     
                    684:     StrAllocCopy (the_choice, choice);                /* Remember it as is, */
                    685:     if (the_choice[strlen(the_choice)-1] == '\n')            /* The final \n */
                    686:        the_choice[strlen(the_choice)-1] = '\0';
1.14      frystyk   687:     
1.40      frystyk   688: #ifdef VM  /* Clear the screen (on screen-mode systems) */
                    689:     clear_screen();
                    690: #endif 
                    691:     this_word = strtok (choice, " \t\n\r");          /* Tokenize user input */
                    692:     this_command = the_choice;
                    693:     if (this_word) {
                    694:        next_word = strtok (NULL, " \t\n\r");
                    695:        other_words = the_choice + (next_word - choice);
1.14      frystyk   696:     }
1.40      frystyk   697:     else
                    698:        goto down;                              /* Empty input : scroll down */
                    699:     
                    700:     /* Process Command */
                    701:   loop:
                    702:     switch (TOUPPER(*this_word)) {
                    703:       case '0':
                    704:       case '1':
                    705:       case '2':
                    706:       case '3':
                    707:       case '4':
                    708:       case '5':
                    709:       case '6':
                    710:       case '7':
                    711:       case '8':
                    712:       case '9':
                    713:        sscanf(this_word,"%d",&ref_num);
                    714:        if (ref_num>0 && ref_num<=HText_sourceAnchors(HTMainText)) {
                    715:            HTAnchor *destination;
                    716:            HTChildAnchor *source = HText_childNumber(HTMainText, ref_num);
                    717:            HTRequest *newreq = Thread_new(YES);
1.44    ! frystyk   718:            if (!source) {
        !           719:                status = EVENT_QUIT;                            /* No anchor */
        !           720:            } else {
        !           721:                destination = HTAnchor_followMainLink((HTAnchor*) source);
        !           722:                HTMainAnchor = HTAnchor_parent((HTAnchor *) source);
        !           723:                HTLoadAnchor(destination, newreq);
        !           724:                free(the_choice);
        !           725:                return EVENT_OK;
        !           726:            }
        !           727:        } else {
        !           728:            if (TRACE || HTInteractive)
        !           729:                fprintf(stderr, "Warning: Invalid Reference Number: (%d)\n",
        !           730:                        ref_num);
1.40      frystyk   731:        }
1.44    ! frystyk   732:        goto ret;
1.40      frystyk   733:        break;
                    734:        
                    735:       case 'B':                
                    736:        if (Check_User_Input("BACK")) {           /* Return to previous node */
                    737:            if (HTHistory_canBacktrack()) {
                    738:                HTLoadAnchor(HTHistory_backtrack(), actreq);
                    739:            } else {
                    740:                printf("\n  The BACK command cannot be used,");
                    741:                printf(" as there are no previous documents\n"); 
                    742:            }
                    743:        }
                    744:        else if (Check_User_Input("BOTTOM")) {          /* Scroll to bottom  */
                    745:            HText_scrollBottom(HTMainText);
                    746:        }
                    747:        goto ret;
                    748:        break;
                    749:        
                    750: #ifdef unix
                    751:       case 'C':
                    752:        if (Check_User_Input("CD"))            /* Change working directory ? */
                    753:            goto lcd;
                    754:        break;
                    755: #endif
                    756:        
                    757:       case 'D':
                    758:        if (Check_User_Input("DOWN")) {             /* Scroll down one page  */
                    759:          down:
                    760:            if (HText_canScrollDown(HTMainText))
                    761:                HText_scrollDown(HTMainText);
                    762:            goto ret;
                    763:        }
                    764:        break;
                    765:        
                    766:       case 'E':                               /* Quit program ? Alternative command */
                    767:        if (Check_User_Input("EXIT"))
                    768:            goto stop;
                    769:        break;
                    770:        
                    771:       case 'F':                                                 /* Keyword search ? */
                    772:        if (is_index && Check_User_Input("FIND")) {
                    773:          find:
                    774:            if (next_word && HTSearch(other_words, HTMainAnchor, actreq))
                    775:                HTHistory_record((HTAnchor *) HTMainAnchor);
                    776:            goto ret;
                    777:        }
                    778:        break;
                    779:        
                    780:       case 'G':
                    781:        if (Check_User_Input("GOTO")) {                              /* GOTO */
                    782:            if (next_word) {
                    783:                HTRequest *newreq = Thread_new(YES);
                    784:                HTLoadRelative(next_word, HTMainAnchor, newreq);
1.44    ! frystyk   785:                goto ret;
1.40      frystyk   786:            }
                    787:        }
                    788:        break;
                    789:        
                    790:       case '?':
                    791:        help_screen();
                    792:        goto ret;
                    793:        
                    794:       case 'H':
                    795:        if (Check_User_Input("HELP")){                       /* help menu, ..*/
                    796:            help_screen();                        /*!! or a keyword search ? */
                    797:            goto ret; 
                    798:        }
                    799:        else if (Check_User_Input("HOME")) {                    /* back HOME */
                    800:            if (!HTHistory_canBacktrack()){ 
                    801:                HText_scrollTop(HTMainText);
                    802:            } else {
                    803:                HTLoadAnchor(HTHistory_recall(1), actreq);
                    804:                /* !! this assumes history is kept.*/
                    805:            }
                    806:            goto ret;
                    807:        }
                    808:        break;
                    809:        
                    810:       case 'K':                                                 /* Keyword search ? */
                    811:        if (is_index && Check_User_Input("KEYWORDS")) {
                    812:            goto find;
                    813:        }
                    814:        break;
                    815:        
                    816:       case 'L':
                    817:        if (Check_User_Input("LIST")){               /* List of references ? */
                    818:            Reference_List(!OutSource);
                    819:            goto ret;
                    820:        }
                    821: #ifdef unix
                    822:        else if (Check_User_Input ("LCD")) {           /* Local change dir ? */
                    823:            extern int chdir();
                    824:          lcd:
                    825:            if (!next_word) {                            /* Missing argument */
                    826:                printf ("\nName of the new local directory missing.\n");
                    827:                goto ret;
                    828:            }
                    829:            if (chdir (next_word)) {                     /* failed : say why */
                    830:                fprintf (stderr, "\n  ");
                    831:                perror (next_word);
                    832:            }
                    833:            else {                  /* Success : display new local directory */
                    834:                /* AS Sep 93 */
                    835: #ifdef NO_GETWD     /* No getwd() on this machine */
                    836: #ifdef HAS_GETCWD   /* System V variant SIGN CHANGED TBL 921006 !! */
                    837:                printf ("\nLocal directory is now:\n %s\n",
                    838:                        getcwd (choice, sizeof(choice)));
                    839: #else   /* has NO getcwd */
                    840:                ErrMsg("This platform does not support getwd() or getcwd()",
                    841:                       NULL);
                    842: #endif /* has no getcwd */
                    843: #else   /* has getwd */
                    844:                printf("\nLocal directory is now:\n %s\n",
                    845:                       (char *) getwd (choice));
                    846: #endif  /* has getwd */
                    847:                /* End AS Sep 93 */
                    848:            }
                    849:            goto ret;
                    850:        }
                    851: #endif
                    852:        break;
                    853:        
                    854:       case 'M':
                    855:        if (Check_User_Input("MANUAL")) {                /* Read User manual */
                    856:            if (HTLoadRelative(MANUAL, HTMainAnchor, actreq))
                    857:                HTHistory_record((HTAnchor *) HTMainAnchor);
                    858:            goto ret;
                    859:        }
                    860:        break;
                    861:        
                    862:       case 'N':                    
                    863:        if (Check_User_Input("NEXT")) {
                    864:            if (!HTHistory_canMoveBy(1)) {       /* No nodes to jump back to */
                    865:                printf("\n  Can't take the NEXT link from the last");
                    866:                if (!HTHistory_canBacktrack())
                    867:                    printf(" document as there is no last");
                    868:                printf(" document.\n");
                    869:                goto ret; 
                    870:            }
                    871:            HTLoadAnchor(HTHistory_moveBy(1), actreq);
                    872:            goto ret;
                    873:        }
                    874:        break;
                    875:        
                    876:       case 'P':                    
                    877:        if (Check_User_Input("PREVIOUS")) {
                    878:            if (!HTHistory_canMoveBy(-1)){ 
                    879:                printf("\n  Can't take the PREVIOUS link from the last");
                    880:                if (!HTHistory_canBacktrack())
                    881:                    printf(" document as there is no last");
                    882:                printf(" document.\n");
                    883:                goto ret;
                    884:            }
                    885:            HTLoadAnchor(HTHistory_moveBy(-1), actreq);
                    886:            goto ret;
                    887:        }
                    888: #ifdef GOT_SYSTEM          
                    889:        else if (!HTClientHost && Check_User_Input("PRINT")) {
                    890:            char * address = HTAnchor_address((HTAnchor *) HTMainAnchor);
                    891:            char * command;
                    892:            char * template = (char*)getenv("WWW_PRINT_COMMAND");
                    893:            int result;
                    894:            
                    895:            if (!template) template = "www -n -na -p66 '%s' | lpr";
                    896:            command = (char *) malloc(strlen(address)+strlen(template)+20);
                    897:            sprintf(command, template, address);
                    898:            result = system(command);
                    899:            free(address);
                    900:            free(command);
                    901:            if (result) printf("  %s\n  returns %d\n", command, result);
                    902:            goto ret;
                    903:        }
                    904: #endif
                    905:        /* this command prints the entire current text to the
                    906:           terminal's printer; at the end it displays the top of the text */
                    907: #ifdef SLAVE_PRINTER
                    908: #define SLAVE_PRINTER_ON  "\033\133\065\151"
                    909: #define SLAVE_PRINTER_OFF "\033\133\064\151"
                    910:        
                    911:        if (Check_User_Input("PS")) {
                    912:            printf ("%s",SLAVE_PRINTER_ON);
                    913:            printf("\f");                          /* Form feed for new page */
                    914:            HText_scrollTop(HTMainText);
                    915:            while(HText_canScrollDown(HTMainText)) {
                    916:                HText_scrollDown(HTMainText);
                    917:            }
                    918:            printf("\f");  /* Form feed for new page */
                    919:            printf ("%s",SLAVE_PRINTER_OFF);
                    920:            HText_scrollTop(HTMainText);
                    921:            goto ret;
                    922:        }       
                    923: #endif
                    924:        break;
                    925:        
                    926:       case 'Q':                                                   /* Quit program ? */
                    927:        if (Check_User_Input("QUIT")) {
                    928: #ifdef VM
                    929:            if (HTHistory_canBacktrack()){       /* Means one level only */
                    930:                HTLoadAnchor(HTHistory_backtrack(), actreq);
                    931:                goto ret;
                    932:            } else {
                    933:                goto stop;                            /* On last level, exit */
                    934:            }
                    935: #endif
                    936:            
                    937:            /*  JFG 9/7/92, following a complaint of 'q' mis-typed for '1'.
                    938:                JFG Then made optional because I hate it !!!
                    939:                TBL made it only affect remote logged on users. 921122 */
                    940:            
                    941:            if (HTClientHost && (strcasecomp(this_word, "quit") != 0) ) {
                    942:                printf ("\n Please type \"quit\" in full to leave www.\n");
                    943:                goto ret;
                    944:            }
                    945:            goto stop;
                    946:        }
                    947:        break;
                    948:        
                    949:       case 'R':        
                    950: #ifdef VM
                    951:        if (Check_User_Input("RETURN"))                /* Means quit program */
                    952:            goto stop;
                    953: #endif     
                    954:        if (Check_User_Input("RECALL")) {
                    955:            int  recall_node_num;
                    956:            
                    957:            if (!HTHistory_canBacktrack()) {           /* No nodes to recall */
                    958:                printf("\n  No other documents to recall.\n");
                    959:                goto ret;
                    960:            }
                    961:            
                    962:            /* Previous node number exists, or does the user just */
                    963:            /* require a list of nodes visited? */
                    964:            if (next_word) {
                    965:                if ((recall_node_num = atoi(next_word)) > 0)  /* Parm OK */
                    966:                    HTLoadAnchor(HTHistory_recall(recall_node_num),
                    967:                                 actreq);
                    968:                else
                    969:                    ErrMsg("Bad command, for list of commands type help.",
                    970:                           this_command);
                    971:            }
                    972:            else 
                    973:                History_List();
                    974:            goto ret;
                    975:        } else if (Check_User_Input("REFRESH")) {
                    976:            HText_select(HTMainText);                      /* Refresh screen */
                    977:            goto ret;
                    978:        }
                    979:        break;
                    980:        
                    981:       case 'S':                                                       /* TBL 921009 */
                    982:        if (Check_User_Input("SOURCE")) {                 /* Apply to source */
                    983:            if (!next_word) goto ret;        /* Should refresh as source @@@ */
                    984:            OutSource = YES;                     /* Load and print as source */
                    985:            this_word = next_word;                       /* Move up one word */
                    986:            next_word = strtok (NULL, " \t\n\r");
                    987:            this_command = the_choice + (this_word - choice);
                    988:            other_words = the_choice + (next_word - choice);
                    989:            goto loop;                                 /* Go treat as before */
                    990:        } else if (Check_User_Input("SET")) {                      /* config */
                    991:            HTSetConfiguration(other_words);
                    992:            goto ret;
                    993:        }
                    994:        break;
                    995:        
                    996:       case 'T':
                    997:        if (Check_User_Input("TOP")) {                     /* Return to top  */
                    998:            HText_scrollTop(HTMainText);
                    999:            goto ret;
                   1000:        }
                   1001:        break;
                   1002:        
                   1003:       case 'U':
                   1004:        if (Check_User_Input("UP")) {                 /* Scroll up one page  */
                   1005:            HText_scrollUp(HTMainText);
                   1006:            goto ret;
                   1007:        }
                   1008:        break;
                   1009:        
                   1010:       case 'V':
                   1011:        if (Check_User_Input("VERBOSE")) {           /* Switch verbose mode  */
                   1012:            WWW_TraceFlag = WWW_TraceFlag ? 0 : OldTraceFlag;
                   1013:            printf ("\n  Verbose mode %s.\n", WWW_TraceFlag ? "ON":"OFF");
                   1014:            goto ret;
                   1015:        }
                   1016:        break;
                   1017:        
                   1018:       case 'Z':
1.44    ! frystyk  1019:        HText_select(HTMainText);                          /* Refresh screen */
        !          1020:        status = EVENT_INTR_ALL;
        !          1021:        goto ret;
        !          1022:        break;
1.40      frystyk  1023: 
                   1024:       case '>':
                   1025:        if (!HTClientHost) {
                   1026:            SaveOutputStream(this_word, next_word);
                   1027:            goto ret;
                   1028:        }
                   1029:        break;
1.1       timbl    1030:        
1.40      frystyk  1031: #ifdef GOT_PIPE
                   1032:       case '|':
                   1033:        if (!HTClientHost) {                               /* Local only!!!! */
                   1034:            char * address = HTAnchor_address((HTAnchor *) HTMainAnchor);
                   1035:            char * command;
                   1036:            int result;
                   1037:            command = (char*) malloc(strlen(address) +strlen(this_command)+30);
                   1038:            
                   1039: #ifdef VM      
                   1040:            sprintf(command, "PIPE CMS WWW %s \"%s\" | %s",
                   1041:                    OutSource ? "-source" : "-n -na -p", address,this_command);
                   1042: 
                   1043: #else  
                   1044:            sprintf(command, "www %s \"%s\" %s", 
                   1045:                    OutSource ? "-source" : "-n -na -p", address,this_command);
                   1046: #endif
                   1047:            printf("Command: %s\n", command);
                   1048:            result = system(command);
                   1049:            if (result)
                   1050:                printf("  %s  returns %d\n", command, result);
                   1051:            free(command);
                   1052:            free(address);
                   1053:            goto ret;
1.14      frystyk  1054:        }
1.40      frystyk  1055: #endif
                   1056:            
                   1057: #ifdef GOT_SYSTEM
                   1058:       case '!':
                   1059:        if (!HTClientHost) {                                  /* Local only! */
                   1060:            int result;
                   1061:            ErrMsg("Executing", this_command);
                   1062:            result = system(strchr(this_command, '!') + 1);
                   1063:            if (result) printf("  %s  returns %d\n",
                   1064:                               strchr(this_command, '!') + 1, result);
                   1065:            goto ret;
1.1       timbl    1066:        }
                   1067: #endif
1.40      frystyk  1068:       default:
                   1069:        break;
                   1070:     } /* Switch on 1st character */
                   1071:        
                   1072:     if (is_index && *this_word) {           /* No commands, search keywords */
                   1073:        next_word = other_words = this_command;
                   1074:        goto find;
                   1075:     } else {             
                   1076:        ErrMsg("Bad command, for list of commands type help.", this_command);
1.14      frystyk  1077:     }
1.1       timbl    1078:        
1.40      frystyk  1079:   ret:
                   1080:     MakeCommandLine(is_index);
                   1081:     free (the_choice);
1.44    ! frystyk  1082:     return status;
1.1       timbl    1083:        
1.40      frystyk  1084:   stop:
                   1085:     free(the_choice);
                   1086:     return EVENT_QUIT;
                   1087: }
                   1088: 
                   1089: 
                   1090: /*                                                     HTEventRequestTerminate
1.1       timbl    1091: **
1.40      frystyk  1092: **     React to the status of the terminated request
1.1       timbl    1093: */
1.40      frystyk  1094: PUBLIC HTEventState HTEventRequestTerminate ARGS2(HTRequest *, actreq,
                   1095:                                                  int,          status) 
                   1096: {
                   1097:     BOOL is_index = HTAnchor_isIndex(HTMainAnchor);
                   1098:     if (status == HT_LOADED) {
                   1099:        if (actreq->parentAnchor) {
                   1100:            HTParentAnchor *parent = actreq->parentAnchor;
                   1101:            HTParentAnchor *destination = actreq->anchor;
                   1102:            HTHistory_leavingFrom((HTAnchor *) parent);
                   1103:            HTHistory_record((HTAnchor *) destination);
                   1104:            actreq->parentAnchor = NULL;
1.14      frystyk  1105:        }
1.1       timbl    1106: 
1.40      frystyk  1107:        /* Now generate the new prompt line as a function of the result */
                   1108:        if (!HText_canScrollDown(HTMainText) &&
                   1109:            !HTAnchor_hasChildren(HTMainAnchor) && !is_index &&
                   1110:            (!HTHistory_canBacktrack())) {
                   1111:            ErrMsg("No way out of here, so I exit!", NULL);         
                   1112:            return EVENT_QUIT;                   /* Exit if no other options */
                   1113:        }
                   1114:        HText_setStale(HTMainText);                /* We corrupt the display */
                   1115:        MakeCommandLine(is_index);
                   1116:     } else if (!HTMainText)                          /* If first try failed */
                   1117:        return EVENT_QUIT;
                   1118:     return EVENT_OK;
                   1119: }
1.1       timbl    1120: 
1.40      frystyk  1121: /* ------------------------------------------------------------------------- */
                   1122: /*                               MAIN PROGRAM                               */
                   1123: /* ------------------------------------------------------------------------- */
1.1       timbl    1124: 
1.40      frystyk  1125: int main ARGS2(int, argc, char **, argv)
                   1126: {
                   1127:     int                return_status = 0;      
                   1128:     int                arg;                           /* Argument number as we scan */
                   1129:     BOOL       argument_found = NO;
                   1130:     BOOL       logfile_flag = NO;
                   1131:     BOOL       first_keyword = YES;
                   1132:     char *     default_default = HTFindRelatedName();
                   1133:     HTFormat   input_format = WWW_HTML;                 /* Used with filter */
                   1134:     HTEventCallBack user;              /* To register STDIN for user events */
1.1       timbl    1135: 
1.40      frystyk  1136: #ifdef THINK_C /* command line from Think_C */
                   1137:     int i;
                   1138:     argc=ccommand(&argv);
                   1139: #endif
                   1140:     
                   1141:     /* HWL 18/7/94: applied patch from
                   1142:        agl@glas2.glas.apc.org (Anton Tropashko) */
                   1143: #ifdef CYRILLIC
                   1144:     arc.locale=0; arc.encoding=0; arc.i_encoding=0; doinull();
1.1       timbl    1145: #endif
                   1146: 
1.40      frystyk  1147: #ifdef VMS
                   1148:     output = stdout;
                   1149: #endif /* VMS */
1.1       timbl    1150:        
1.40      frystyk  1151:     request =  HTRequest_new();
                   1152: 
                   1153:     /* Check for command line options */
                   1154:     *keywords = '\0';
                   1155:     for (arg=1; arg<argc ; arg++) {
                   1156:        if (*argv[arg] == '-') {
                   1157: 
                   1158:            /* - alone => filter */
                   1159:            if (argv[arg][1] == 0) {
                   1160:                filter = YES;      
                   1161:                HTInteractive = NO;     /* From stdin, Force non-interactive */
                   1162:            
                   1163:            /* -? or -help: show the command line help page */
                   1164:            } else if (!strcmp(argv[arg], "-?") ||
                   1165:                       !strcmp(argv[arg], "-help")) {
                   1166:                home_anchor = (HTParentAnchor *)
                   1167:                    HTAnchor_findAddress(COM_HELP_FILE);
                   1168:                argument_found = YES;       /* Don't try to find other pages */
                   1169: 
                   1170:            /* from -- Initial represntation (only with filter) */
                   1171: 
                   1172:            } else if (!strcmp(argv[arg], "-from")) {
                   1173:                input_format = (arg+1 >= argc || *argv[arg+1] == '-') ?
                   1174:                    WWW_HTML : HTAtom_for(argv[++arg]);
                   1175: 
                   1176: #ifdef CYRILLIC
                   1177:            /* HWL 18/7/94: applied patch from agl@glas2.glas.apc.org
                   1178:               (Anton Tropashko) */
                   1179:            } else if (!strcmp(argv[arg], "-koi2alt")) {
                   1180:                doia2k(); printf("Ahak2a!");
                   1181: #endif
                   1182: 
                   1183:            /* Page size */
                   1184:            } else if (!strncmp(argv[arg], "-p", 2)) {
                   1185:                if (*(argv[arg]+2)) {
                   1186:                    if (sscanf(argv[arg]+2, "%d", &HTScreenHeight) < 1)
                   1187:                        HTScreenHeight = -1;            
                   1188:                    else {
                   1189:                        if(HTScreenHeight < MIN_SCREEN_HEIGHT)
                   1190:                            HTScreenHeight = MIN_SCREEN_HEIGHT;
                   1191:                        if(HTScreenHeight > MAX_SCREEN_HEIGHT)
                   1192:                            HTScreenHeight = MAX_SCREEN_HEIGHT;
                   1193:                    }
                   1194:                } else if (arg+1 < argc && *argv[arg+1] != '-') {
                   1195:                    if (sscanf(argv[++arg], "%d", &HTScreenHeight) < 1)
                   1196:                        HTScreenHeight = -1;
                   1197:                    else {
                   1198:                        if(HTScreenHeight < MIN_SCREEN_HEIGHT)
                   1199:                            HTScreenHeight = MIN_SCREEN_HEIGHT;
                   1200:                        if(HTScreenHeight > MAX_SCREEN_HEIGHT)
                   1201:                            HTScreenHeight = MAX_SCREEN_HEIGHT;
                   1202:                    }
                   1203:                }
1.1       timbl    1204: 
1.40      frystyk  1205:            /* Page width */
                   1206:            } else if (!strncmp(argv[arg], "-w", 2)) {
                   1207:                if (*(argv[arg]+2)) {
                   1208:                    if (sscanf(argv[arg]+2, "%d", &HTScreenWidth) < 1)
                   1209:                        HTScreenWidth = SCREEN_WIDTH;
                   1210:                } else if (arg+1 < argc && *argv[arg+1] != '-') {
                   1211:                    if (sscanf(argv[++arg], "%d", &HTScreenWidth) < 1)
                   1212:                        HTScreenWidth = SCREEN_WIDTH;
1.14      frystyk  1213:                }
1.40      frystyk  1214:                if(HTScreenWidth < MIN_SCREEN_WIDTH)
                   1215:                    HTScreenWidth = MIN_SCREEN_WIDTH;
                   1216:                if(HTScreenWidth > MAX_SCREEN_WIDTH)
                   1217:                    HTScreenWidth = MAX_SCREEN_WIDTH;
                   1218:                    
                   1219:            /* reformat html */
                   1220:            } else if (!strcmp(argv[arg], "-reformat")) {
                   1221:                request->output_format = WWW_HTML;
                   1222:                    HTInteractive = NO;
                   1223:                    reformat_html = YES;
1.1       timbl    1224: 
1.40      frystyk  1225:            /* to -- Final represntation */
                   1226:            } else if (!strcmp(argv[arg], "-to")) {
                   1227:                request->output_format =
                   1228:                    (arg+1 >= argc || *argv[arg+1] == '-') ?
                   1229:                        WWW_PRESENT : 
                   1230:                        HTAtom_for(argv[++arg]);
                   1231:                    HTInteractive = NO;                 /* JFG */
1.1       timbl    1232: 
1.40      frystyk  1233:            /* Telnet from */
                   1234:            } else if (!strcmp(argv[arg], "-h")) {
                   1235:                if (arg+1 < argc && *argv[arg+1] != '-') {
                   1236:                    HTClientHost = argv[++arg];             /* Use host name */
1.14      frystyk  1237:                }
1.40      frystyk  1238: 
                   1239:            /* Log file */
                   1240:            } else if (!strcmp(argv[arg], "-l")) {
                   1241:                if (arg+1 < argc && *argv[arg+1] != '-')
                   1242:                    logfile_root = argv[++arg];
                   1243:                logfile_flag = YES;
                   1244:                    
                   1245:            /* List References */
                   1246:            } else if (!strcmp(argv[arg], "-listrefs")) {
                   1247:                listrefs_option = YES;
                   1248:                HTInteractive = NO;                     /* non-interactive */
                   1249: 
                   1250:            /* Method Used (Currently on GET and HEAD are supported) */
                   1251:            } else if (!strcmp(argv[arg], "-m")) {
                   1252:                HTInteractive = NO;
                   1253:                if (++arg < argc) {
                   1254:                    if (!strcasecomp(argv[arg], "head")) {
                   1255:                        request->method = METHOD_HEAD;
                   1256:                        request->output_format = WWW_MIME;
                   1257:                    } else if (!strcasecomp(argv[arg], "get"))
                   1258:                        request->method = METHOD_GET;
                   1259:                    else
                   1260:                        request->method = METHOD_INVALID;
1.1       timbl    1261:                }
1.40      frystyk  1262: 
                   1263:            /* Non-interactive */
                   1264:            } else if (!strcmp(argv[arg], "-n")) {
                   1265:                HTInteractive = NO;
                   1266: 
                   1267:            /* Output filename */
                   1268:            } else if (!strcmp(argv[arg], "-o")) { 
                   1269:                output_file_name = (arg+1 < argc && *argv[arg+1] != '-') ?
                   1270:                    argv[++arg] : DEFAULT_OUTPUT_FILE;
                   1271:                    HTInteractive = NO;
                   1272:                    
                   1273:            /* Anchor format */
                   1274:            } else if (!strcmp(argv[arg], "-a")) { 
                   1275:                if (arg+1 < argc && *argv[arg+1] != '-')
                   1276:                    end_reference = argv[++arg];      /* New representation */
                   1277: 
                   1278:            /* Anchor format */
                   1279:            } else if (!strcmp(argv[arg], "-ar")) { 
                   1280:                if (arg+1 < argc && *argv[arg+1] != '-')
                   1281:                    reference_mark = argv[++arg];  /* Change representation */
                   1282: 
                   1283:            /* Anchor format */
                   1284:            } else if (!strcmp(argv[arg], "-as")) { 
                   1285:                if (arg+1 < argc && *argv[arg+1] != '-')
                   1286:                    start_reference = argv[++arg]; /* Change representation */
                   1287: 
                   1288:            /* No anchors */
                   1289:            } else if (!strcmp(argv[arg], "-na")) { 
                   1290:                    display_anchors = NO;
                   1291: 
                   1292: #ifndef NO_RULES
                   1293:            } else if (!strcmp(argv[arg], "-r")) {
                   1294:                if (arg+1 < argc && *argv[arg+1] != '-') { 
                   1295:                    if (HTLoadRules(argv[++arg]) < 0) {
                   1296:                        ErrMsg("Can't open rule file", argv[arg]);
                   1297:                        return_status = -1;
                   1298:                        goto endproc;
                   1299:                    }
1.14      frystyk  1300:                }
1.1       timbl    1301: #endif
1.40      frystyk  1302: #ifndef NO_DIR_OPTIONS
                   1303:            } else if (!strncmp(argv[arg], "-d", 2)) {
                   1304:                char *p = argv[arg]+2;
                   1305:                for(;*p;p++) {
                   1306:                    switch (argv[arg][2]) {
                   1307:                    case 'b':   HTDirReadme = HT_DIR_README_BOTTOM; break;
                   1308:                    case 'n':   HTDirAccess = HT_DIR_FORBID; break;
                   1309:                    case 'r':   HTDirReadme = HT_DIR_README_NONE; break;
                   1310:                    case 's':   HTDirAccess = HT_DIR_SELECTIVE; break;
                   1311:                    case 't':   HTDirReadme = HT_DIR_README_TOP; break;
                   1312:                    case 'y':   HTDirAccess = HT_DIR_OK; break;
                   1313:                    default:
                   1314:                        ErrMsg("Bad parameter for directory listing -d option",
                   1315:                               argv[arg]);
                   1316:                        return_status = -4;
                   1317:                        goto endproc;
                   1318:                    }
                   1319:                } /* loop over characters */
                   1320: #endif
                   1321:            /* Reference list heading */
                   1322:            } else if (!strcmp(argv[arg], "-refhead")) { 
                   1323:                if (arg+1 < argc && *argv[arg+1] != '-')
                   1324:                    refhead = argv[++arg];
1.1       timbl    1325: 
1.40      frystyk  1326:            /* Print version and exit */
                   1327:            } else if (!strcmp(argv[arg], "-version")) { 
                   1328:                printf("WWW LineMode Browser version %s (WWW Library %s)\n",
                   1329:                            VL, HTLibraryVersion);
                   1330:                goto endproc;                           
1.1       timbl    1331: 
1.40      frystyk  1332: #ifdef TRACE
                   1333:           /* Verify: Turns on trace */
                   1334:            } else if (!strncmp(argv[arg], "-v", 2)) {
                   1335:                char *p = argv[arg]+2;
                   1336:                WWW_TraceFlag = 0;
                   1337:                for(; *p; p++) {
                   1338:                    switch (*p) {
                   1339:                      case 'a': WWW_TraceFlag += SHOW_ANCHOR_TRACE; break;
                   1340:                      case 'p': WWW_TraceFlag += SHOW_PROTOCOL_TRACE; break;
                   1341:                      case 's': WWW_TraceFlag += SHOW_SGML_TRACE; break;
                   1342:                      case 't': WWW_TraceFlag += SHOW_THREAD_TRACE; break;
                   1343:                      case 'u': WWW_TraceFlag += SHOW_URI_TRACE; break;
                   1344:                      default:
                   1345:                        ErrMsg("Bad parameter for verbose mode", argv[arg]);
                   1346:                    }
                   1347:                }/* loop over characters */
                   1348:                if (!WWW_TraceFlag)
                   1349:                    WWW_TraceFlag = SHOW_ALL_TRACE;
                   1350:                OldTraceFlag = WWW_TraceFlag;            /* Remember setting */
1.1       timbl    1351: #endif
1.14      frystyk  1352:            
1.40      frystyk  1353:            /* Source please */
                   1354:            } else if (!strcmp(argv[arg], "-source")) {
                   1355:                    request->output_format = WWW_SOURCE;
                   1356:                    HTInteractive = NO;                 /* JFG */
                   1357: 
                   1358: #ifdef THINK_C
                   1359:            /* Echo to file */
                   1360:            } else if (!strcmp(argv[arg], "-e")){
                   1361:                struct tm *tm_now; time_t time_now;
                   1362:                cecho2file("ThinkCconsole",FALSE,stdout);
                   1363:                time_now=time(NULL);tm_now=localtime(&time_now);
                   1364:                printf("\n--------------------------------------------"
                   1365:                        "\n Time: %d.%.2d.%.2d %d:%d:%d\n"
                   1366:                        "--------------------------------------------\n",
                   1367:                        (*tm_now).tm_year,
                   1368:                        (*tm_now).tm_mon+1,
                   1369:                        (*tm_now).tm_mday,
                   1370:                        (*tm_now).tm_hour,
                   1371:                        (*tm_now).tm_min,
                   1372:                        (*tm_now).tm_sec);
                   1373:     
                   1374:            /* debug socket library */
                   1375:            } else if (!strcmp(argv[arg], "-s")) {
                   1376:                socketdebug=1;
1.1       timbl    1377: #endif
1.40      frystyk  1378:              /* endif long list of argument options */
1.1       timbl    1379: 
1.40      frystyk  1380:            } else {
                   1381:                ErrMsg("Bad Command Line Argument", argv[arg]);
                   1382:            }
                   1383:        } else {           /* If no leading `-' then check for main argument */
                   1384:            if (!argument_found) {
                   1385:                char * ref = HTParse(argv[arg], default_default, PARSE_ALL);
                   1386:                home_anchor = (HTParentAnchor*) HTAnchor_findAddress(ref);
                   1387:                free(ref);
                   1388:                argument_found = YES;
                   1389:            } else {               /* Check for successive keyword arguments */
                   1390:                if (first_keyword) {                    /* Collect keywords */
                   1391:                    first_keyword = NO;
1.14      frystyk  1392:                } else {
1.40      frystyk  1393:                    strcat(keywords, " ");
1.14      frystyk  1394:                }
1.40      frystyk  1395:                strcat(keywords,HTStrip(argv[arg]));
                   1396:            } /* argument already found */
                   1397:        } /* Not an option '-'*/
                   1398:     } /* End of argument loop */
                   1399: 
                   1400:     /* Initialization */
1.44    ! frystyk  1401:     HTLibInit();
1.40      frystyk  1402:     if (HTClientHost) HTSecure = YES;             /* Access to local files? */
                   1403:     HTEnableFrom = YES;                             /* Send `From:' in the request? */
                   1404:     if (HTScreenHeight == -1) {                                /* Default page size */
                   1405:        if (HTInteractive) {
                   1406: #ifdef GET_SCREEN_SIZE
                   1407:            int scr_height, scr_width;
                   1408:            scrsize(&scr_height, &scr_width);
                   1409:            HTScreenHeight = scr_height;
                   1410: #else
1.42      frystyk  1411:            HTScreenHeight = SCREEN_HEIGHT;
1.1       timbl    1412: #endif
1.40      frystyk  1413:        } else
1.42      frystyk  1414:            HTScreenHeight = 999999;
1.40      frystyk  1415:     }
1.23      frystyk  1416: 
1.40      frystyk  1417:     /* Enable local directory access */
                   1418:     HTDirReadme = HT_DIR_README_TOP;                 /* Readme presentation */
                   1419:     HTDirAccess = HTClientHost ? HT_DIR_SELECTIVE : HT_DIR_OK;  /* browsing */
1.1       timbl    1420: 
1.40      frystyk  1421: #ifndef NO_RULES
                   1422:     {
                   1423:        char * rules = getenv("WWW_CONFIG");
                   1424:        if (rules && HTLoadRules(rules) < 0) {
                   1425:            ErrMsg("Cant't open rule file", rules);
                   1426:        }
                   1427:     }
                   1428: #endif
1.1       timbl    1429: 
1.40      frystyk  1430:     /* Force predefined presentations etc to be set up */
                   1431:     if (HTInteractive)
                   1432:        HTFormatInit(request->conversions);
                   1433:     else
                   1434:        HTFormatInitNIM(request->conversions);
1.4       timbl    1435: 
1.40      frystyk  1436:     /* Open output file */
                   1437:     if (!HTInteractive)        {
                   1438:        if (output_file_name) {
                   1439:            FILE * fp = fopen(output_file_name, "w");
                   1440:            if (!fp) {
                   1441:                ErrMsg("Can't open file for writing", output_file_name);
                   1442:                return_status = -3;
                   1443:                goto endproc;
1.14      frystyk  1444:            }
1.40      frystyk  1445:            output = fp;
                   1446:        }
                   1447:        request->output_stream = HTFWriter_new(output, 
                   1448:                                               output == stdout ? YES : NO);  
                   1449:        /* Just pump to stdout but YES: leave it open */
                   1450:        
                   1451:        /*      To reformat HTML, just put it through a parser running
                   1452:        **      into a regenerator   tbl 940613 */
                   1453:        
                   1454:        if (reformat_html) {
                   1455:            request->output_stream = SGML_new(&HTMLP_dtd,
                   1456:                                  HTMLGenerator(request->output_stream));
1.1       timbl    1457: 
1.40      frystyk  1458:        }
                   1459:     }
                   1460:     
                   1461:     /* Open Log File. Logfile via Telnet is now optional (HENRIK 11/02-94) */
                   1462:     if (logfile_flag) {
                   1463:         if(!logfile_root)
                   1464:             logfile_root = HTClientHost ?
                   1465:                DEFAULT_LOGFILE : DEFAULT_LOCAL_LOGFILE;
                   1466:        HTLogFileName = (char*) malloc(strlen(logfile_root)+20);
1.14      frystyk  1467: 
1.40      frystyk  1468: #ifdef NO_GETPID
                   1469:        sprintf(HTLogFileName, "%s", logfile_root);  /* No getpid() */
                   1470: #else
                   1471:        sprintf(HTLogFileName, "%s-%d", logfile_root, (int) getpid());
1.14      frystyk  1472: #endif
1.40      frystyk  1473:        HTlogfile = fopen(HTLogFileName, "a");
                   1474:        if (!HTlogfile)
                   1475:            ErrMsg("Can't open log file", HTLogFileName);
                   1476:     };
1.14      frystyk  1477: 
1.40      frystyk  1478:     /* Make home page address */
                   1479:     if (!home_anchor)
                   1480:        home_anchor = HTHomeAnchor();
1.1       timbl    1481: 
1.40      frystyk  1482:     /* Now we are ready to start the program! If in interactive mode then start
                   1483:        the event loop which will run until the program terminates */
                   1484:     if (filter) {                                   /* Just convert formats */
                   1485:        HTBindAnchor((HTAnchor*)home_anchor, request);
                   1486:        HTParseSocket(input_format, 0, request);      /* From std UNIX input */
                   1487:            goto endproc;
                   1488:     }
                   1489:     if (HTInteractive) {
                   1490:        reqlist = HTList_new();
                   1491:        user.sockfd = STDIN_FILENO;
                   1492:        user.callback = EventHandler;
                   1493:        HTList_addObject(reqlist, (void *) request);
                   1494:        HTEventRegister(&user);
                   1495:        return_status = HTEventLoop(request, home_anchor,
                   1496:                                    (keywords && *keywords) ? keywords : NULL);
                   1497:     } else {
                   1498:        if (((keywords && *keywords) ?
                   1499:             HTSearch(keywords, home_anchor, request) :
                   1500:             HTLoadAnchor((HTAnchor*) home_anchor, request)) != HT_LOADED) {
                   1501:            char *addr = HTAnchor_address((HTAnchor *) home_anchor);
                   1502:            ErrMsg("Can't access document", addr);
                   1503:            free(addr);
                   1504:            if (!HTMainText) {
                   1505:                return_status = -2;                  /* Can't get first page */
                   1506:            } else if (listrefs_option) {
                   1507:                Reference_List(NO);                   /* List without titles */
1.14      frystyk  1508:            }
1.1       timbl    1509:        }
1.34      frystyk  1510:     }
1.18      frystyk  1511: 
1.40      frystyk  1512: endproc:
1.44    ! frystyk  1513:     HTLibTerminate();
1.40      frystyk  1514:     Thread_deleteAll();
                   1515:     if(default_default)
                   1516:        free(default_default);
1.18      frystyk  1517: 
1.40      frystyk  1518:     if(!return_status) {                       /* Everything is working :-) */
                   1519: #ifdef VMS 
                   1520:        return 1;
                   1521: #else
                   1522:        return 0;       /* Good */
                   1523: #endif
1.18      frystyk  1524:     }
1.40      frystyk  1525:     return return_status;                     /* An error occured somewhere */
1.14      frystyk  1526: }
1.1       timbl    1527: 
1.18      frystyk  1528: /* End HTBrowse.c */
1.14      frystyk  1529: 

Webmaster