1 #include "mrilib.h"
2 #include "xutil.h"
3 
4 #ifdef DONT_USE_HTMLWIN  /*-------------------- dummy routines ------------------------------*/
5 
new_MCW_htmlwin(Widget w,char * m,void_func * kf,XtPointer kd,MCW_action_items * mai,int nact)6 MCW_htmlwin * new_MCW_htmlwin( Widget w, char *m, void_func *kf, XtPointer kd ,
7                                MCW_action_items *mai, int nact){ return NULL ; }
MCW_htmlwin_alter(MCW_htmlwin * hw,char * mmm)8 void MCW_htmlwin_alter( MCW_htmlwin *hw, char *mmm ){ return ; }
9 
convert_text_to_html(char * txt)10 char * convert_text_to_html( char *txt ){ return txt; }  /* 06 May 2015 */
11 
12 #else                    /*---------- non-dummy routines --------------------*/
13 
14 #include "XmHTML/XmHTML.h"
15 #include "debugtrace.h"    /* 12 Mar 2001 */
16 
17 extern int afni_uses_selenium(void) ;
18 extern int selenium_open_webpage(char *) ;
19 
20 XmImageConfig *_xmimage_cfg = NULL ;
21 
22 
23 static void MCW_htmlwinkill_CB( Widget , XtPointer , XtPointer ) ;
24 static void MCW_htmlwin_CB    ( Widget , XtPointer , XtPointer ) ;
25 
26 static MCW_action_item HWIN_act[] = {
27  { "Quit" , MCW_htmlwin_CB , NULL , NULL , "Close window" , 0 } ,
28 } ;
29 
30 /*----------------------------------------------------------------------------*/
31 /* Not sure what this is for! */
32 
armCB(Widget w,XtPointer arg1,XmAnyCallbackStruct * href_data)33 static void armCB( Widget w, XtPointer arg1, XmAnyCallbackStruct *href_data)
34 {
35    XButtonEvent *event;
36 
37    event             = (XButtonEvent*)href_data->event ;
38    event->window     = DefaultRootWindow(XtDisplay(w)) ;
39    event->root       = DefaultRootWindow(XtDisplay(w)) ;
40    event->subwindow  = DefaultRootWindow(XtDisplay(w)) ;
41    event->send_event = True ;
42 
43    XUngrabPointer( XtDisplay(w) , CurrentTime ) ;
44    XSendEvent( XtDisplay(w) , DefaultRootWindow(XtDisplay(w)) ,
45                True , ButtonPressMask , (XEvent *)event        ) ;
46    XFlush(XtDisplay(w)) ;
47 }
48 
49 /*----------------------------------------------------------------------------*/
50 /* For dealing with clicks on links (anchors). */
51 
anchorCB(Widget widget,XtPointer client_data,XmHTMLAnchorCallbackStruct * cbs)52 static void anchorCB( Widget widget, XtPointer client_data,
53                       XmHTMLAnchorCallbackStruct *cbs      )
54 {
55 ENTRY("anchorCB") ;
56 
57   switch( cbs->url_type ){
58 
59     case ANCHOR_JUMP:                                /* internal jumps */
60       cbs->doit = True ; cbs->visited = True ;
61     break ;
62 
63     default:
64     case ANCHOR_HTTP:{                               /* external http links */
65       static char *webb=NULL ; static int first=1 ;
66       if( first == 1 ){ webb = GetAfniWebBrowser() ; first = 2 ; }
67       if( afni_uses_selenium() ) {
68          selenium_open_webpage(cbs->href);
69       }
70       else{
71          if( webb != NULL ){
72            char *cmd = (char *)malloc( strlen(webb) + strlen(cbs->href) + 32 ) ;
73            sprintf( cmd , "%s '%s' &" , webb , cbs->href ) ;
74            system( cmd ) ; free( cmd ) ;
75          } else if( first == 2 ){
76              INFO_message("No command line Web browser program found in your path.") ;
77            ININFO_message("Set environment variable AFNI_WEB_BROWSER to the full"  ) ;
78            ININFO_message("pathname of a browser than can be started from the Unix") ;
79            ININFO_message("command line -- e.g., '/usr/local/bin/mozilla'"         ) ;
80            first = 0 ;
81          }
82       }
83     }
84     break ;
85   }
86 
87   EXRETURN ;
88 }
89 
90 /*----------------------------------------------------------------------------*/
91 
92 #undef  SSUB
93 #define SSUB(a,b)                                        \
94  do{ char *qqq = string_substitute( mmm , (a) , (b) ) ;  \
95      if( qqq != NULL ){ free(mmm) ; mmm = qqq ; }        \
96  } while(0)
97 
98 #undef  NSUB
99 #define NSUB(a) SSUB((a),"\0")
100 
101 #undef  UOSUB
102 #undef  UXSUB
103 #define UOSUB(a) SSUB((a),"<u>")
104 #define UXSUB(a) SSUB((a),"</u>")
105 
unfontize(char * msg)106 static char * unfontize( char *msg )
107 {
108    char *mmm , *qqq ;
109 
110    if( msg == NULL || *msg == '\0' ) return msg ;
111 
112    mmm = strdup(msg) ;
113    NSUB("<small>"); NSUB("</small>");
114    UOSUB("<big>") ; UXSUB("</big>") ;
115    UOSUB("<h1>")  ; UXSUB("</h1>")  ;
116    UOSUB("<h2>")  ; UXSUB("</h2>")  ;
117    UOSUB("<h3>")  ; UXSUB("</h3>")  ;
118    UOSUB("<h4>")  ; UXSUB("</h4>")  ;
119    UOSUB("<h5>")  ; UXSUB("</h5>")  ;
120    UOSUB("<h6>")  ; UXSUB("</h6>")  ;
121    UOSUB("<i>")   ; UXSUB("</i>")   ;
122    UOSUB("<b>")   ; UXSUB("</b>")   ;
123    UOSUB("<em>")  ; UXSUB("</em>")  ;
124    UOSUB("<tt>")  ; UXSUB("</tt>")  ;
125    SSUB("<font ","<u ") ; UXSUB("</font>") ;
126    SSUB("&nbsp;",".") ;
127 
128    if( strcmp(mmm,msg) == 0 ){ free(mmm) ; mmm = msg ; }
129    return mmm ;
130 }
131 
132 /*----------------------------------------------------------------------------*/
133 /* Mangle a message to be good HTML for display */
134 
htmlize(char * msg)135 static char * htmlize( char *msg )
136 {
137    char *mmm=NULL ; int dounf ;
138 
139 ENTRY("htmlize") ;
140 
141    if( msg == NULL || *msg == '\0' ){
142      msg = strdup("<html><body><p>Dummy\n<p>Message</body></html>") ;
143      RETURN(msg) ;
144    }
145 
146    if( strncmp(msg,"<html>",6) == 0 ) RETURN(msg) ;     /* already HTML format */
147 
148    if( strncmp(msg,"file:",5) == 0 ){      /* read file */
149      char *qqq=AFNI_suck_file(msg+5) ; char *dnam , *repl , *targ ;
150      if( qqq != NULL )
151        mmm = qqq ;
152      else
153        mmm = strdup("<html><body><h1>Dummy</h1><h2>Message</h2></body></html>");
154 
155      /* edit file to add base directory to all '<img src=' filenames */
156 
157      if( strchr(msg+5,'/') != NULL && strstr(mmm,"<img src=") != NULL ){
158        dnam = strdup(msg+5) ; qqq  = THD_trailname(dnam,0) ;
159        if( qqq != NULL && qqq != dnam ){
160          *qqq = '\0' ;                          /* dnam is now base directory */
161          repl = (char *)malloc(sizeof(char)*(strlen(dnam)+16)) ;
162          targ = "<img src=\"" ;                       /* string to search for */
163          sprintf( repl , "%s%s" , targ , dnam ) ;       /* replacement string */
164          qqq = string_substitute( mmm , targ , repl ) ;        /* do the work */
165          if( qqq != NULL ){ free(mmm) ; mmm = qqq ; }
166          free(repl) ;
167        }
168        free(dnam) ;
169      }
170 
171    } else if( strncmp(msg,"wami:",5) == 0 ){      /* wami love */
172       mmm = (char *)malloc(sizeof(char)*(strlen(msg)+64)) ;
173       strcpy(mmm,"<html><body>\n") ;
174       strcat(mmm,msg+strlen("wami:")) ;
175       strcat(mmm,"\n</body></html>") ;
176    } else {                                                 /* add HTML stuff */
177      mmm = (char *)malloc(sizeof(char)*(strlen(msg)+64)) ;
178      strcpy(mmm,"<html><body>\n") ;
179      strcat(mmm,msg) ;
180      strcat(mmm,"\n</body></html>") ;
181    }
182 
183 #ifdef UNFONTIZE_HTMLWIN
184    dounf = 1 ;
185 #else
186    dounf = AFNI_yesenv("AFNI_UNFONTIZE_HTML") ;
187 #endif
188    if( dounf ){
189      char *qqq = unfontize(mmm) ;
190      if( qqq != mmm ){ free(mmm) ; mmm = qqq ; }
191    }
192 
193    RETURN(mmm) ;
194 }
195 
196 /*----------------------------------------------------------------------------*/
197 /* This is a callback to deal with some refresh problems
198    that should have been handled by the XmHTML library.
199    For now this call is not needed. It looks like the patching
200    of XmHTML did the trick ZSS March 2012 */
201 
RefreshHTML_AtEvent(Widget w,XtPointer client_data,XEvent * ev,RwcBoolean * continue_to_dispatch)202 void RefreshHTML_AtEvent( Widget w , XtPointer client_data ,
203                   XEvent * ev , RwcBoolean * continue_to_dispatch )
204 {
205 #if 0
206     XmHTMLRefresh(client_data);
207 #endif
208 }
209 
210 /*----------------------------------------------------------------------------*/
211 /* Open a window with an XmHTML widget containing msg.
212    If msg starts with "file:", then it indicates a file to read and display.
213    Otherwise, it is the content of the page directly.
214 *//*--------------------------------------------------------------------------*/
215 
new_MCW_htmlwin(Widget wpar,char * msg,void_func * kill_func,XtPointer kill_data,MCW_action_item * umai,int nact)216 MCW_htmlwin * new_MCW_htmlwin( Widget wpar , char *msg ,
217                                void_func *kill_func , XtPointer kill_data,
218                                MCW_action_item *umai, int nact)
219 
220 {
221    int wx,hy,xx,yy , xp,yp , scr_width,scr_height , xr,yr , xpr,ypr , ii ;
222    int swid , shi ;
223    Position xroot , yroot ;
224    Screen *scr ;
225    Arg wa[64] ; int na ; Widget ws ;
226    char *wtype = "help" ;
227    MCW_htmlwin *hw ;
228    char *mymsg ;
229    MCW_action_item *mai=NULL;
230    static Pixel afg=(Pixel)0 , afgv=(Pixel)0 ;
231 
232 ENTRY("new_MCW_htmlwin") ;
233 
234    /*-- sanity check --*/
235 
236    if( wpar == NULL || !XtIsRealized(wpar) || msg == NULL || *msg == '\0' )
237      RETURN(NULL) ;
238 
239 
240    /*-- set position based on parent and screen geometry --*/
241 
242    MCW_widget_geom( wpar , &wx,&hy,&xx,&yy ) ;     /* geometry of parent */
243    XtTranslateCoords( wpar, 0,0, &xroot,&yroot ) ; /* root coords */
244    xr = (int) xroot ; yr = (int) yroot ;
245 
246    scr        = XtScreen(wpar) ;
247    scr_width  = WidthOfScreen(scr) ;
248    scr_height = HeightOfScreen(scr) ;
249 
250    xp = xx+8 ;  xpr = xr+8 ;
251         if( xpr+50 > scr_width ){ xp -= 100 ; xpr -= 100 ; } /* too right */
252    else if( xpr+10 < 0 )        { xpr = xp = 1 ; }           /* too left  */
253 
254    yp = yy+hy+8 ;  ypr = yr+hy+8 ;
255         if( ypr+50 > scr_height ){ yp = yy-8 ; ypr = yr-100 ;} /* too down */
256    else if( ypr+10 < 0 )         { ypr = yp = 1 ;            } /* too up   */
257 
258    /*-- create a popup shell --*/
259 
260    hw = myXtNew(MCW_htmlwin) ;
261    hw->kill_func = kill_func ;
262    hw->kill_data = kill_data ;
263 
264    hw->wshell = XtVaCreatePopupShell(
265                  wtype , xmDialogShellWidgetClass , wpar ,
266                     XmNx , xpr ,
267                     XmNy , ypr ,
268                     XmNborderWidth , 0 ,
269                     XmNborderColor , 0 ,
270                     XmNinitialResourcesPersistent , False ,
271                  NULL ) ;
272 
273    XmAddWMProtocolCallback(
274         hw->wshell ,
275         XmInternAtom( XtDisplay(hw->wshell) , "WM_DELETE_WINDOW" , False ) ,
276         MCW_htmlwinkill_CB , (XtPointer)hw ) ;
277 
278    /*-- create a form to hold everything else --*/
279 
280    hw->wtop = XtVaCreateWidget(
281                 wtype , xmFormWidgetClass , hw->wshell ,
282                   XmNborderWidth , 0 ,
283                   XmNborderColor , 0 ,
284                   XmNtraversalOn , True  ,
285                   XmNinitialResourcesPersistent , False ,
286                 NULL ) ;
287 
288    /*-- create action area --*/
289 
290    if (!umai) { /* default action item */
291       mai = HWIN_act; nact = 1;
292       for( ii=0 ; ii < nact ; ii++ ){
293         mai[ii].data     = (XtPointer)hw ;
294         mai[ii].make_red = 0 ;
295       }
296       mai[nact-1].make_red = 1 ;
297    } else {
298       /* use user preference */
299       mai = umai;
300    }
301 
302    hw->wactar = MCW_action_area( hw->wtop , mai , nact ) ;
303 
304    XtVaSetValues( hw->wactar ,
305                      XmNleftAttachment , XmATTACH_FORM ,
306                      XmNrightAttachment, XmATTACH_FORM ,
307                      XmNtopAttachment  , XmATTACH_FORM ,
308                      XmNtopOffset      , 4 ,
309                   NULL ) ;
310 
311    /*-- frame to hold HTML widget --*/
312 
313    hw->wframe = XtVaCreateManagedWidget(
314                   wtype , xmFrameWidgetClass, hw->wtop ,
315                   XmNtopAttachment   , XmATTACH_WIDGET ,
316                   XmNtopWidget       , hw->wactar ,
317                   XmNtopOffset       , 5 ,
318                   XmNleftAttachment  , XmATTACH_FORM,
319                   XmNleftOffset      , 2 ,
320                   XmNbottomAttachment, XmATTACH_FORM,
321                   XmNbottomOffset    , 2 ,
322                   XmNrightAttachment , XmATTACH_FORM,
323                   XmNrightOffset     , 2,
324                   XmNshadowType      , XmSHADOW_IN,
325                   XmNshadowThickness , 5 ,
326                 NULL ) ;
327 
328    /*---- create HTML area ----*/
329 
330    if( afg == (Pixel)0 ){
331      afg  = XmHTMLAllocColor( hw->wtop, "#ffdd00", WhitePixelOfScreen(XtScreen(hw->wtop)) ) ;
332      afgv = XmHTMLAllocColor( hw->wtop, "#ffcc99", WhitePixelOfScreen(XtScreen(hw->wtop)) ) ;
333    }
334 
335    swid = WidthOfScreen(XtScreen(wpar))  - 222 ; if( swid > 799 ) swid = 799 ;
336    shi  = HeightOfScreen(XtScreen(wpar)) - 222 ; if( shi  > 899 ) shi  = 899 ;
337 
338    mymsg = htmlize(msg) ;  /* edit the text */
339 
340 STATUS("create HTML widget") ;
341 
342    hw->whtml = XtVaCreateManagedWidget(
343                   wtype , xmHTMLWidgetClass , hw->wframe ,
344                   XmNmarginWidth       , 8 ,
345                   XmNmarginHeight      , 8 ,
346                   XmNwidth             , swid ,
347                   XmNheight            , shi ,
348                   XmNvalue             , mymsg,
349                   XmNfontFamily        , "adobe-helvetica-normal-*" ,
350                   XmNfontFamilyFixed   , "adobe-courier-normal-*" ,
351                   XmNfontSizeFixedList , "14,10" ,
352                   XmNanchorButtons     , False ,
353                   XmNanchorForeground        , afg  ,
354                   XmNanchorVisitedForeground , afgv ,
355                 NULL ) ;
356    XtAddCallback( hw->whtml, XmNactivateCallback, (XtCallbackProc)anchorCB, NULL ) ;
357    XtAddCallback( hw->whtml, XmNarmCallback     , (XtCallbackProc)armCB   , NULL ) ;
358 
359 #if 0 /* This was needed to deal with some refreshing problems when the scrollbar
360          was moved. The patch in XmHTML seems to have do the trick. These are
361          left here should we need to reuse them someday */
362    XtInsertEventHandler( hw->whtml ,        /* notify when */
363                          LeaveWindowMask ,  /* pointer leaves */
364                          FALSE ,            /* this window */
365                          RefreshHTML_AtEvent,
366                          (XtPointer) hw->whtml ,
367                          XtListTail ) ;     /* last in queue */
368    XtInsertEventHandler( hw->whtml ,        /* notify when */
369                          EnterWindowMask ,  /* pointer leaves */
370                          FALSE ,            /* this window */
371                          RefreshHTML_AtEvent,
372                          (XtPointer) hw->whtml ,
373                          XtListTail ) ;     /* last in queue */
374 #endif
375 
376 STATUS("manage HTML widgets") ;
377 
378    XtManageChild( hw->wtop ) ;
379 
380 #if 0
381    XtVaSetValues( hw->wshell , XmNwidth,swid , XmNheight,shi , NULL ) ;
382 #endif
383 
384    /*--- open the window for viewing, and place it on the screen ---*/
385 
386    XtPopup( hw->wshell , XtGrabNone ) ; RWC_sleep(16) ;
387 
388    RWC_visibilize_widget( hw->wshell ) ;
389 
390    RWC_xineramize( XtDisplay(hw->wshell) ,
391                    xpr,ypr,swid,shi , &xpr,&ypr ) ;
392 
393    XtVaSetValues( hw->wshell, XmNx,xpr , XmNy,ypr , NULL ) ;
394 
395    hw->shell_width = swid ; hw->shell_height = shi ;
396 
397    NORMAL_cursorize( hw->wshell ) ;
398 
399 #if 0
400    XmHTMLTextSetString( hw->whtml , mymsg ) ;
401 #endif
402 
403    if( mymsg != msg ) free(mymsg) ;               /* toss the trash */
404 
405 STATUS("force HTML redisplay") ;
406 
407    RWC_sleep(66) ; XmHTMLRedisplay( hw->whtml ) ; /* force redraw to be safe */
408 
409    RETURN(hw) ;
410 }
411 
412 /*-------------------------------------------------------------------------*/
413 /* replace the contents of an MCW_htmlwin (not tested) */
414 
MCW_htmlwin_alter(MCW_htmlwin * hw,char * mmm)415 void MCW_htmlwin_alter( MCW_htmlwin *hw , char *mmm )
416 {
417    int swid , shi ;
418    char *msg ;
419 
420 ENTRY("MCW_htmlwin_alter") ;
421 
422    if( hw == NULL || mmm == NULL || *mmm == '\0' ) EXRETURN ;
423    msg = htmlize(mmm) ;
424 
425    XmHTMLTextSetString( hw->whtml , msg ) ;
426 
427    if( msg != mmm ) free(msg) ;
428 
429    EXRETURN ;
430 }
431 
432 /*-------------------------------------------------------------------------*/
433 /* Called when the user presses an action button */
434 
MCW_htmlwin_CB(Widget w,XtPointer client_data,XtPointer call_data)435 static void MCW_htmlwin_CB( Widget w, XtPointer client_data, XtPointer call_data )
436 {
437    MCW_htmlwin *hw = (MCW_htmlwin *)client_data ;
438    char *wname     = XtName(w) ;
439 
440 ENTRY("MCW_htmlwin_CB") ;
441 
442    if( client_data == NULL ) EXRETURN ;
443 
444    if( strcmp(wname,"Quit") == 0 ){
445       if( hw->kill_func != NULL )
446         AFNI_CALL_VOID_1ARG( hw->kill_func , XtPointer , hw->kill_data ) ;
447       XtDestroyWidget( hw->wshell ) ;
448       myXtFree( hw ) ;
449       EXRETURN ;
450    }
451 
452    EXRETURN ;
453 }
454 
455 /*-------------------------------------------------------------------------*/
456 /* Called when the user kills the window via the window manager controls */
457 
MCW_htmlwinkill_CB(Widget w,XtPointer client_data,XtPointer call_data)458 static void MCW_htmlwinkill_CB( Widget w, XtPointer client_data, XtPointer call_data )
459 {
460    MCW_htmlwin *hw = (MCW_htmlwin *) client_data ;
461 
462 ENTRY("MCW_htmlwinkill_CB") ;
463 
464    if( hw->kill_func != NULL )
465      AFNI_CALL_VOID_1ARG( hw->kill_func , XtPointer , hw->kill_data ) ;
466    XtDestroyWidget( hw->wshell ) ;
467    myXtFree( hw ) ;
468    EXRETURN ;
469 }
470 
471 /*--------------------------------------------------------------------*/
472 
473 #define HTTP_check(str) ( strncmp((str),"http://",7) == 0  &&              \
474                           !isspace((str)[7])               &&              \
475                           !iscntrl((str)[7])               &&              \
476                           (str)[7] != '\0'                 &&              \
477                           (str)[7] != '*'                  &&              \
478                           (str)[7] != '.'                     )
479 
480 #define HTTPS_check(str) ( strncmp((str),"https://",8) == 0  &&            \
481                            !isspace((str)[8])                &&            \
482                            !iscntrl((str)[8])                &&            \
483                            (str)[8] != '\0'                  &&            \
484                            (str)[8] != '*'                   &&            \
485                            (str)[8] != '.'                     )
486 
487 #define CHK4(abcd)                                                         \
488   ( tolower(buf[hend-4])==abcd[0] && tolower(buf[hend-3])==abcd[1] &&      \
489     tolower(buf[hend-2])==abcd[2] && tolower(buf[hend-1])==abcd[3]   )
490 
491 #define EMIT_char(ch)                                                      \
492  do{ if( itout == atout ){                                                 \
493        atout = (int)(1.5f*atout+1024); tout = (char *)realloc(tout,atout); \
494      }                                                                     \
495      tout[itout++] = (ch) ;                                                \
496  } while(0)
497 
498 #define EMIT_string(cs)                                                    \
499  do{ char *cq ;                                                            \
500      for( cq=cs ; *cq != '\0' ; cq++ ) EMIT_char(*cq) ;                    \
501  } while(0)
502 
503 /*----------------------------------------------------------------------------*/
504 /* Convert plain text to HTML, inserting links and a few other miscellany.
505    free() the returned string when done, if you don't mind.  [06 May 2015]
506 *//*--------------------------------------------------------------------------*/
507 
convert_text_to_html(char * txt)508 char * convert_text_to_html( char *txt )
509 {
510    char *tout=NULL , tbuf[2048] , *tin=txt , cc ;
511    int  itout=0 , atout=0 ;
512 
513 ENTRY("convert_text_to_html") ;
514 
515    if( txt == NULL || *txt == '\0' ) RETURN(tout) ; /* bad input */
516 
517    atout = strlen(txt)+1024 ;  /* size of output buffer */
518     tout = (char *)malloc(atout) ; itout = 0 ;
519 
520    EMIT_string("<html>\n"
521                "<head>\n"
522                "<title>AFNI Papers</title>\n"
523                "</head>\n"
524                "<body>\n<br />\n" ) ;
525 
526 #if 0
527    EMIT_string("<center><img src=\"afnigui_logo.jpg\" align=middle></center>\n") ;
528 #endif
529 
530    while( *tin != '\0' ){
531 
532 #if 0
533      /* some HTML already? just pass it thru */
534 
535      if( *tin == '<' && ( isalpha(*(tin+1)) || *(tin+1) == '/') ){  /* "<something...>" */
536        do{
537          EMIT_char(*tin) ; tin++ ;
538        } while( *tin != '>' && *tin != '\0' ) ;
539        if( *tin == '>' ){ EMIT_char(*tin) ; tin++ ; }
540        continue ;
541      }
542 #endif
543 
544      /* link to a web page? "http://something" */
545 
546      if( HTTP_check(tin) ){
547        int hend , ii ;
548 
549        /* scan forward to get to end of 'http://something' string at hend */
550 
551        for( hend=7 ; tin[hend] != '\0' && !isspace(tin[hend]) ; hend++ ) ; /*nada*/
552 
553        /* insert hyperlink here*/
554 
555        EMIT_string("<a href=\"") ;
556        for( ii=0 ; ii < hend ; ii++ )  EMIT_char(tin[ii]);
557        EMIT_string("\">") ;
558        for( ii=0 ; ii < hend ; ii++ )  EMIT_char(tin[ii]);
559        EMIT_string("</a>") ;
560 
561        tin += hend ; continue ;
562      }
563 
564      /* link to a web page? "https://something" [08 Apr 2016] */
565 
566      if( HTTPS_check(tin) ){
567        int hend , ii ;
568 
569        /* scan forward to get to end of 'https://something' string at hend */
570 
571        for( hend=8 ; tin[hend] != '\0' && !isspace(tin[hend]) ; hend++ ) ; /*nada*/
572 
573        /* insert hyperlink here*/
574 
575        EMIT_string("<a href=\"") ;
576        for( ii=0 ; ii < hend ; ii++ )  EMIT_char(tin[ii]);
577        EMIT_string("\">") ;
578        for( ii=0 ; ii < hend ; ii++ )  EMIT_char(tin[ii]);
579        EMIT_string("</a>") ;
580 
581        tin += hend ; continue ;
582      }
583 
584      /* a single normal character */
585 
586      cc = *tin ;
587           if( cc == ' ' ) EMIT_string("&nbsp;")   ;   /* put in HTML escapes */
588      else if( cc == '&' ) EMIT_string("&amp;")    ;   /* for special cases */
589      else if( cc == '<' ) EMIT_string("&lt;")     ;
590      else if( cc == '>' ) EMIT_string("&gt;")     ;
591      else if( cc == '\n') EMIT_string("<br />\n") ;
592      else                 EMIT_char  (cc)         ;   /* perfectly normal character */
593      tin++ ;
594    }
595 
596    EMIT_string("\n</body></html>\n") ;
597    EMIT_char('\0') ;
598    RETURN(tout) ;
599 }
600 
601 #endif /* DONT_USE_HTMLWIN */
602