aboutsummaryrefslogblamecommitdiffstats
path: root/main.c
blob: 1ea0f87d36e21c73a23342da79d8e49f28ec4c50 (plain) (tree)
1
2
3
4
5
6
7
8
9
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
5568
5569
5570
5571
5572
5573
5574
5575
5576
5577
5578
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
                                                        






                      
                                                
                     
      
                 

                    
                  
                





                                             
                                                                               



                           

                                    





                



                    
                        


                                       
                



                                     


                                            
               



                                                  

      



                                           








                                        
                                                                      
                                                              
                                     

                            
 

                                                          
 
                              

                                  
                                 



                  
                                  
 
                             
                            



                                                            

                                          
                              






                                 










                                                           


                    


























                         





                                  





                     
            







                    


                     



           
                         
 
                




                                                                             
                                                                                          



                                                   
                                                      






                                                               
                
                                                            
                                               
                                                                    



                                                                                              



                                                                                         
                                                                         

                                                                                

                                                                          

                                                                                           

                                                                           


                                                          
                
                                                         
                                               
                 

                                                                                
                                                
                                                              


                                                                     
                                                                         





                                                                       

                                                                               

                                                                       

                                                                  
                                                    

                       











                                             
                        





                                     



                            
 


                                                               
 



                                                       
 

                     
 






                                                                               
 

                     
     



                                                 

 
              


                   
               


                   
                                                       
         



                
                                                       
         

     
                  



                              
      

   
                                    



            

                                           
                                       
                            
                    


                                              
                                     
                           

                                                       
                            


                             
 
 












                                        



                               
 
                        
                          
                                                          














                                        
                                          








                                              
                                          

                                   
                                                                         
                       



                                                                              



                         
                             


                                                
                                                                











                                                     
                                                                     





                                              
                                                                         





                                                
                                                                   




                                             
                                                                 



                        
                                                            
                   
                                                            








                                         
                                      






                                              

                                             

                 
                                                                   






                                            



                                                  
                            























                                                           








                                                       
                                                     

                                            
                                                    

                                            
                

                                            
                                               





                                                     






                                                                       










                                              
                                               
                                       
                                                      
                                       
                                                    
                                     




                                                                  
                                         
                                                     
                             
                                    
                                                         






















                                                           
                                                    
                                         













                                                        
             
      



                                                   














                                                                          
                                    


                                      
             
                
                                                     

                                  
                                               


                                                      
                                      


                                                   
                                     
             
                                                


                                                  


                                                                         




                                      







                                            


                                                     
                                               
                                              



                                                           


                                                                 

                                      




















                                                  
                        
                           






                    



                      



                                        
                                  
                               

                               
                   


                      
 


                                      

                    
                    
                         
               
                   
                                          
                 





                                                  
     



                                          


                              


                             
 
                                                            
                       
                         
                              
                         
                                                                            





                                                                              
                                                                     


                                


                                                                          
                                                                           

                                                                
                                       
                                                                                                








                                                                                                                       

                                                                   





                                                                   
                                                                     

                                                                               






                              
                              
                         


                                                    







                                

                                         
                                        

                                                   


                                                                      

                  







                                                   
                                       


















                                                                            

                                 

                                                                       












                                              
                                                                      



                                                                               


                                     
                                              


                                                       
                                           
         


                                            

                       


                                       
                                      


                                          



                                                                

              

                                                            
                                
                  
                             
      
         
     

                   


                                                

     
                                                          

                                  
                                                      
         
                          
                     




                                                

                                                
                            
         
                    
     








                                                               
 

                                        


                          
          
              






                                                




                                                         
                                      





                                                      
                

                           
                                               
                


                                            


                                                 
                                                              
         



                                      
      
               


                                       
         
                                         
      



                                        
                    



                                        


                                      
                


                            
      
                

                             
                                               

                                                                     
                                                          



                                          
                                               
                                          











                              
                                             













                                                        
                        














                                    
                      


                     


                                       
               
     





                                                               
           
                       
 
                                                                          
                     
                                                                       


                                                                          
















                                                    

 








                                                
                                                    
 


                                                 










                               
                                                   












                                
                                                    







               
                          

                      
                                       



                                
                                               



     
                           
 
                                                                 












                                


                 


                                                       

                                           

 
           
                       


              


                            










                                                              
                  





                     
                      










                                           
                                      













                                                       
                      

                       
                              


                                  
 
                      

                          







                                     



                                                  
 

                                              











                             






















                                                                  

          
                                                

                                                                              
                       


                             
      
                                                      














                                    
                    
                                                                               

        

                                                          
                                                






                        
                    
                                                                                

        

                                                            
                                                





               
                                      





                 
                                       








                                                  
                                                                       
                       






                                                                            










                                            
                                                         















                                              









                                      


                                                   

                                  


                                           
                           

                                                      
 


                                       

                                                    

                             
                  

 
    











                                                                     
          
                                            























                                                                   
 
                 


                                       
      
 






                                                     
                                    







                                                      


                                                      
         
            
                                                                  
     
                    

                                   

                                     

                                              
     

                                              
                 
       




                                 
     
      








                                                   
                                                                         





                                                                              
                                              


          

                                                  
 
              
               
 
                                               

                                    
                    
               
                                 

                                            

                                        




                                         
 





                                     





                                       
                                        
 



                                       

 





                                                 
           
                        
 

                      
                                                   


                                     




                                                             



                                        
                                                      

                                            

                                        

                                                                   
















                              
                                      

                            

                                       















                                                      
                                                                         












                                                                   
                                                                        








                                                                   
                                      


                  
                             













                                         
                              


                  
                             







                                        





                      
                                                                 

                                                                  






                                                           

                                                            


                                         










                                        
                                                                 

                                      




                                                                           



                                         

                                                                         



                                 
                                                      
                      
                                                

          



                                                     



                                              










                                                                              





                                            

























                                                                        





                                            





















                                                     




                                                                 
                                                                        
     

                                  




                                      

                 












                                                                   





                                            







                     









                                                                           
                                  
     
                                                       
      






                      
                                                                      
                      
                                                                        










                                                        






                                      
                                  


                                        


          
                                












                              

                                      
                           
                                  


                                        


          
                                                  












                              

                                      
                           
                                


                                        


          
                                                  

 
    
           
 







                              

                                      
                           
                                   


                                        


          
                                
 
 




             








                                                                        
                             


            
                                                           















                                                       
                              



                                      
                             









                                                           

                                                            














                                                                       

                                                       








                                        
                             


            
                                                           
















                                 
                              



                                      
                             














                                                                      
                                                                           
























                                                                       

                                                      







                                        
                                         



                    
             






                                                 
                






































                                                       






                                                              





















                                                          
                             




















                                                                              
                             

                                                                    










                                                       
                 
                     

                                             








































                                                       



                                    

            

                                                                                           
                                                                                                                        





                                                                   
                                  

                                                                          
                                                                              

                                                                            


                     




                                             


                                                                      


                            

                         
 









                                                     
                                                     
                                                 
                                                 
                                                
                                                   



                                                   


                                                   






                                              
               

            

                                         
                    
                                                                    



                              
             
                                                                    
             
                 









                                              
                  
               


                                      
                                           

                                                                             

 






                     
                  
               









                                      
                                          



















                                                    
                  
               










                                      
                                          





















                                                        
                  
               




                                                               

                                             

               
                     




                                                                               
                                                       










                                              
               
                                           







                                                                   
                                                                   





                                             
                                                   







                                                                   
                                                                            
                      
                                                        















                                                                             


                                                                                                         

















                                                                        
                                                                               



















                                                                
                    

                                                                               


                                                                               
                                                      
      






















                                                                   
                                  
                                                



                                                                
                    

                                                                       
                                                                          

                                                                         
      












                                              



                              




                                      










                                                                     

                                          
                           






                                                              
                                                                                 





                                      




                                                          
                                    









                                                             
                 
                                                                      
                                         

                                                  
                                      


               
                                                                               




                                                                       




                                                     














                                                                               
                                               


























                                        
                                                      
              
                                                                      
                      
                                                           







                                        
                     
                                       


































                                                                     
                                           






































                                                                              




                                                                             
                                                                            




                                              
           
                                                                  










                                          


                                                                             
























                                                           



                                                                             
                                                                              
                                           
                                                                          
                                                       
                                                                              
                                           
                                                                          
                                                       
             
                                                                             
                               
                                                                       
                                                
                                                                    



                                                                             
                    
                                                               


                                                                        




                                               



                                                                             


                                                                   
                                                     


                                                                   
                                                    



                                                       


                                                                       



                                                                   
                                                                  
                          


                                                                            

















                                                          



                 
                      

 



                  
                       




                       
            
                   

                          

                         







                                        
                                

                         



                                                                         
                                                                               
                                      






                                                  






                                                                             






                                                  





                                                                         








                                                                               




                                                                         


                                            





                                                                         
                                            

                             





                                                                         




                                            




                                                                           
                                                                             
                  
                                            

                                    





                                                 

                        







                                                                    
                                                     
                                                                





















                                                                   

                                                                                            





                                                                                   
                                                                                                                                                                                                                      
                                             

              

                                                                          


                          

                                                             
                                         

                                           


                                                

                                               
                  


                                                 
                                                     










                                              

                                                                            







                                              
                                   


















                                                                       
                                                                            



                                                             
                                                                            






                                                             
                             















                                     
                                          





















                                                            
                 





                                      



                             






















                                                                         
             





                                      
                              
                 
                          
                                    

                             






















                                                                         
                                    












                                             
                             










                                                                         

                                                                       































                                                                     
                                    












                                             
                             










                                                                         

                                                                       
























                                                                     









                                            
               
                              
               


                                           
                                             





                                






















                                                                    


                    
               















                                            
               
                              
               


                                           
                                             





                                                













                                                                         


                    
               














































                                          
          
                            






                                                                      
                        




















                                                           





                                                      






                          
                                




                                                             
 
                                              




                                          


                                                                              
                                                 

                                                          
                                          
                                                      
             

                                                    


                                  











                                              
                                                         


                




                                                       
                                    









                                                             
                 
                                                                      
                                         

                                                  
                                   


               
                                                                    





                                                                       
              
                                                          
                      
                                                                          











                                                        
           
                                  
 

                              
                                 


                          



















                                                        
         
                                                       
                        

                             







                                                                       







                                                  







                                                              
                                    
                                                      
                                       

                                                                           




           
                                




            
                                        


           
                                                 







                                                                     


                                                         









                                              
                                                






                             

            

                                                         
                                



                                                                               
                                            








                                                              





                   
                                                                 

                                                                  








                                                          

                              
                           



                                                  


                                              































                                                               


               

                    
                                        
                                                


                                                         
               

                              

               
                                                   
                                                      















                                                                               
                                                             






















































                                                                 
                              





                                                                 




                                                                              
     
                                                




                                 



                                                             






                                     
                                                                           














                                        

               



                                                                 
                                             


                                                                       
        
                                                                        
                                             




                                        

                      



                        
                             








                                                   

          



                                                              
                                                                
                        
                                               

                            
                       
             

              
                                                               





                                                

                                                  
                                                                  
        
                                                    





              
                





                       
                














                                                  
                             

                                             
               




                                                   

          


                         

                                                  
                                                                  
        
                                                    








                      
                                                                      
               



                                                         










                                                              
                                              


                                      
                                      





                           

                                                    
                                  

          
























                                                                               
                                  
                                                                          
                           






                                                             
                                                                         

                                                                        


















                                                  



                                    
            












                                                     
                                  



















                                                                

                                               























                                                                              




                                             

                                             
                                                                           


                            

                         
 








                                                   


                                                
                                                     
                                                 
                                                 
                                                
                                                   



                                                   



                                                   




                                              
                         
 
                                   
                                                                                 
                                                  


                                                     
                                                                       



                                                   
                                                                     
                                                                              
      
            
                                                                                                                 
                                                                                                        

                                           


                                       
                                       
     


                              

                              
 



                             


                                              











                                                                  


                                                   
                          
 
                                   
                                              



                                       
                                           
     

                               
 



                              







































                                                                 
            
                         
                    

















                                                                 

                                                  
         

          
                                          
     

                                            
 


                                                                  
               
     

                                                         
             
                           

















































                                                                         


                                                      







                                                                        
                                                           







                                                              







                      
                        



                                                                         


                                              






                     



                                                                         
                                           
                                              


      
                
 













                                                              




                                                             

                 
 

                                    


                              










































                                                                               














































                                                    
                                                                   
                                                                 

                                                           

                                                               
                                                                             




                                                
                                           

                                                               




                                                    









                                                                  


                             
               


                                                           

                           
                                              


                                                   
                         


                                                   
                       

                  

                                            
                                               


                                            
                                               
                   
     
 



                                                                      

          




















                                              

                                      

                   
                                    











                                                    
                                    














































                                                  
                                               

    

         
                                                                     


    











                                               








                                                     
             
                                                                   
 
            
                               
             
 

              

                    
                   
                 
                                                 
            
                                     
                    
          
                                                    
            
                                                     
            














                                                   

 
               


                    
                      
                
 
                                                           


                                            




                                            

                                                                 
                                                              


                                                
          

                                                                      

                                     







                                              
                                            






                                  
                                              
 





                               



                                                   

                                                  
                                              
                                                                 








                                                                
                                            







                                                
                                           



                                             
                                               


                                 
                                            

          

                                                           


     


                   
                      

                                                          




                                                               

                          
                                      
                    
                              

 










                        





                






                                                                               





                                               
               
 
                 
                                                          
      


                   
      
            
 
 









                                                                 



                                                





























                                               



                      

               
                        
                        
                              
                                                              



                             
                                            



                           

                              





                                                                               


                                            
                                                  
                                                
                                                       
                                                              




                                      








                          
 
                                                                 

                                        




                                                                  

                        

                                   
                                              

                   



                                                                           

          
                                                          


                                        



                                                         
                                                   
                                     
                                                                    



                                     

     
      

    








                                     
                         


















                                                                         
                         


























                                              

                                                                               


    















                                                                 
























































































































































































































































































































                                                                               
/* $Id: main.c,v 1.118 2002/11/05 17:10:06 ukai Exp $ */
#define MAINPROGRAM
#include "fm.h"
#include <signal.h>
#include <setjmp.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#if defined(HAVE_WAITPID) || defined(HAVE_WAIT3)
#include <sys/wait.h>
#endif
#include <time.h>
#include "terms.h"
#include "myctype.h"
#include "regex.h"
#ifdef USE_MOUSE
#ifdef USE_GPM
#include <gpm.h>
#endif				/* USE_GPM */
#if defined(USE_GPM) || defined(USE_SYSMOUSE)
extern int do_getch();
#define getch()	do_getch()
#endif				/* defined(USE_GPM) || defined(USE_SYSMOUSE) */
#endif

#define DSTR_LEN	256

static char *config_filename = NULL;

Hist *LoadHist;
Hist *SaveHist;
Hist *URLHist;
Hist *ShellHist;
Hist *TextHist;

typedef struct {
    int cmd;
    void *user_data;
} Event;
#define N_EVENT_QUEUE 10
static Event eventQueue[N_EVENT_QUEUE];
static int n_event_queue;

#ifdef USE_ALARM
static int alarm_sec = 0;
static short alarm_status = AL_UNSET;
static Buffer *alarm_buffer;
static Event alarm_event;
static MySignalHandler SigAlarm(SIGNAL_ARG);
#endif

#ifdef SIGWINCH
static int need_resize_screen = FALSE;
static MySignalHandler resize_hook(SIGNAL_ARG);
static MySignalHandler resize_handler(SIGNAL_ARG);
static void resize_screen(void);
#endif

#ifdef SIGPIPE
static MySignalHandler SigPipe(SIGNAL_ARG);
#endif

#ifdef USE_MARK
static char *MarkString = NULL;
#endif
static char *SearchString = NULL;
int (*searchRoutine) (Buffer *, char *);

JMP_BUF IntReturn;

static void cmd_loadfile(char *path);
static void cmd_loadURL(char *url, ParsedURL *current, char *referer);
static void cmd_loadBuffer(Buffer *buf, int prop, int linkid);
static void keyPressEventProc(int c);
int show_params_p = 0;
void show_params(FILE * fp);

static char *getCurWord(Buffer *buf, int *spos, int *epos,
			const char *badchars);

static int display_ok = FALSE;
static void dump_source(Buffer *);
static void dump_head(Buffer *);
static void dump_extra(Buffer *);
int prec_num = 0;
int prev_key = -1;
int on_target = 1;

void set_buffer_environ(Buffer *);

static void _followForm(int);
static void _goLine(char *);
static void _newT(void);
static void followTab(TabBuffer *tab);
static void moveTab(TabBuffer *t, TabBuffer *t2, int right);
static int check_target = TRUE; 
#define PREC_NUM (prec_num ? prec_num : 1)
#define PREC_LIMIT 10000
static int searchKeyNum(void);

#include "gcmain.c"

#define help() fusage(stdout, 0)
#define usage() fusage(stderr, 1)

static void
fversion(FILE * f)
{
    fprintf(f, "w3m version %s, options %s\n", w3m_version,
#if LANG == JA
	    "lang=ja"
#ifdef KANJI_SYMBOLS
	    ",kanji-symbols"
#endif
#else
	    "lang=en"
#endif
#ifdef USE_IMAGE
	    ",image"
#endif
#ifdef USE_COLOR
	    ",color"
#ifdef USE_ANSI_COLOR
	    ",ansi-color"
#endif
#endif
#ifdef USE_MOUSE
	    ",mouse"
#ifdef USE_GPM
	    ",gpm"
#endif
#ifdef USE_SYSMOUSE
	    ",sysmouse"
#endif
#endif
#ifdef USE_MENU
	    ",menu"
#endif
#ifdef USE_COOKIE
	    ",cookie"
#endif
#ifdef USE_SSL
	    ",ssl"
#ifdef USE_SSL_VERIFY
	    ",ssl-verify"
#endif
#endif
#ifdef USE_EXTERNAL_URI_LOADER
	    ",external-uri-loader"
#endif
#ifdef USE_W3MMAILER
	    ",w3mmailer"
#endif
#ifdef USE_NNTP
	    ",nntp"
#endif
#ifdef USE_GOPHER
	    ",gopher"
#endif
#ifdef INET6
	    ",ipv6"
#endif
#ifdef USE_ALARM
	    ",alarm"
#endif
#ifdef USE_MARK
	    ",mark"
#endif
#ifdef USE_MIGEMO
	    ",migemo"
#endif
	);
}

static void
fusage(FILE * f, int err)
{
    fversion(f);
    fprintf(f, "usage: w3m [options] [URL or filename]\noptions:\n");
    fprintf(f, "    -t tab           set tab width\n");
    fprintf(f, "    -r               ignore backspace effect\n");
    fprintf(f, "    -l line          # of preserved line (default 10000)\n");
#ifdef JP_CHARSET
#ifndef DEBIAN			/* disabled by ukai: -s is used for squeeze multi lines */
    fprintf(f, "    -e               EUC-JP\n");
    fprintf(f, "    -s               Shift_JIS\n");
    fprintf(f, "    -j               JIS\n");
#endif
    fprintf(f, "    -O e|s|j|N|m|n   display code\n");
    fprintf(f, "    -I e|s           document code\n");
#endif				/* JP_CHARSET */
    fprintf(f, "    -B               load bookmark\n");
    fprintf(f, "    -bookmark file   specify bookmark file\n");
    fprintf(f, "    -T type          specify content-type\n");
    fprintf(f, "    -m               internet message mode\n");
    fprintf(f, "    -v               visual startup mode\n");
#ifdef USE_COLOR
    fprintf(f, "    -M               monochrome display\n");
#endif				/* USE_COLOR */
    fprintf(f, "    -F               automatically render frame\n");
    fprintf(f,
	    "    -cols width      specify column width (used with -dump)\n");
    fprintf(f,
	    "    -ppc count       specify the number of pixels per character (4.0...32.0)\n");
#ifdef USE_IMAGE
    fprintf(f,
	    "    -ppl count       specify the number of pixels per line (4.0...64.0)\n");
#endif
    fprintf(f, "    -dump            dump formatted page into stdout\n");
    fprintf(f,
	    "    -dump_head       dump response of HEAD request into stdout\n");
    fprintf(f, "    -dump_source     dump page source into stdout\n");
    fprintf(f, "    -dump_both       dump HEAD and source into stdout\n");
    fprintf(f,
	    "    -dump_extra      dump HEAD, source, and extra information into stdout\n");
    fprintf(f, "    -post file       use POST method with file content\n");
    fprintf(f, "    -header string   insert string as a header\n");
    fprintf(f, "    +<num>           goto <num> line\n");
    fprintf(f, "    -num             show line number\n");
    fprintf(f, "    -no-proxy        don't use proxy\n");
#ifdef USE_MOUSE
    fprintf(f, "    -no-mouse        don't use mouse\n");
#endif				/* USE_MOUSE */
#ifdef USE_COOKIE
    fprintf(f,
	    "    -cookie          use cookie (-no-cookie: don't use cookie)\n");
#endif				/* USE_COOKIE */
    fprintf(f, "    -pauth user:pass proxy authentication\n");
#ifndef KANJI_SYMBOLS
    fprintf(f, "    -no-graph        don't use graphic character\n");
#endif				/* not KANJI_SYMBOLS */
#ifdef DEBIAN			/* replaced by ukai: pager requires -s */
    fprintf(f, "    -s               squeeze multiple blank lines\n");
#else
    fprintf(f, "    -S               squeeze multiple blank lines\n");
#endif
    fprintf(f, "    -W               toggle wrap search mode\n");
    fprintf(f, "    -X               don't use termcap init/deinit\n");
    fprintf(f,
	    "    -title[=TERM]    set buffer name to terminal title string\n");
    fprintf(f, "    -o opt=value     assign value to config option\n");
    fprintf(f, "    -config file     specify config file\n");
    fprintf(f, "    -help            print this usage message\n");
    fprintf(f, "    -version         print w3m version\n");
    fprintf(f, "    -debug           DO NOT USE\n");
    if (show_params_p)
	show_params(f);
    exit(err);
}

static int option_assigned = 0;
extern void parse_proxy(void);

static GC_warn_proc orig_GC_warn_proc = NULL;
#define GC_WARN_KEEP_MAX (20)

static void
wrap_GC_warn_proc(char *msg, GC_word arg)
{
    if (fmInitialized) {
	/* *INDENT-OFF* */
	static struct {
	    char *msg;
	    GC_word arg;
	} msg_ring[GC_WARN_KEEP_MAX];
	/* *INDENT-ON* */
	static int i = 0;
	static int n = 0;
	static int lock = 0;
	int j;

	j = (i + n) % (sizeof(msg_ring) / sizeof(msg_ring[0]));
	msg_ring[j].msg = msg;
	msg_ring[j].arg = arg;

	if (n < sizeof(msg_ring) / sizeof(msg_ring[0]))
	    ++n;
	else
	    ++i;

	if (!lock) {
	    lock = 1;

	    for (; n > 0; --n, ++i) {
		i %= sizeof(msg_ring) / sizeof(msg_ring[0]);
		disp_message_nsec(Sprintf
				  (msg_ring[i].msg,
				   (unsigned long)msg_ring[i].arg)->ptr, FALSE,
				  1, TRUE, FALSE);
	    }

	    lock = 0;
	}
    }
    else if (orig_GC_warn_proc)
	orig_GC_warn_proc(msg, arg);
    else
	fprintf(stderr, msg, (unsigned long)arg);
}

#ifdef SIGCHLD
static void
sig_chld(int signo)
{
    int p_stat;
#ifdef HAVE_WAITPID
    pid_t pid;

    while ((pid = waitpid(-1, &p_stat, WNOHANG)) > 0) {
	;
    }
#elif HAVE_WAIT3
    int pid;

    while ((pid = wait3(&p_stat, WNOHANG, NULL)) > 0) {
	;
    }
#else
    wait(&p_stat);
#endif
    signal(SIGCHLD, sig_chld);
    return;
}
#endif

Str
make_optional_header_string(char *s)
{
    char *p;
    Str hs;

    if (strchr(s, '\n') || strchr(s, '\r'))
	return NULL;
    for (p = s; *p && *p != ':'; p++) ;
    if (*p != ':' || p == s)
	return NULL;
    hs = Strnew_size(strlen(s) + 3);
    Strcopy_charp_n(hs, s, p - s);
    if (!Strcasecmp_charp(hs, "content-type"))
	override_content_type = TRUE;
    Strcat_charp(hs, ": ");
    if (*(++p)) {		/* not null header */
	SKIP_BLANKS(p);		/* skip white spaces */
	Strcat_charp(hs, p);
    }
    Strcat_charp(hs, "\r\n");
    return hs;
}

int
MAIN(int argc, char **argv, char **envp)
{
    Buffer *newbuf = NULL;
    char *p, c;
    int i;
    InputStream redin;
    char *line_str = NULL;
    char **load_argv;
    FormList *request;
    int load_argc = 0;
    int load_bookmark = FALSE;
    int visual_start = FALSE;
    char search_header = FALSE;
    char *default_type = NULL;
    char *post_file = NULL;
    Str err_msg;

#ifndef HAVE_SYS_ERRLIST
    prepare_sys_errlist();
#endif				/* not HAVE_SYS_ERRLIST */

    srand48(time(0));

    NO_proxy_domains = newTextList();
    fileToDelete = newTextList();

    load_argv = New_N(char *, argc - 1);
    load_argc = 0;

    CurrentDir = currentdir();
    BookmarkFile = NULL;
    rc_dir = expandName(RC_DIR);
    i = strlen(rc_dir);
    if (i > 1 && rc_dir[i - 1] == '/')
	rc_dir[i - 1] = '\0';
    config_filename = rcFile(CONFIG_FILE);
    create_option_search_table();

    /* argument search 1 */
    for (i = 1; i < argc; i++) {
	if (*argv[i] == '-') {
	    if (!strcmp("-config", argv[i])) {
		argv[i] = "-dummy";
		if (++i >= argc)
		    usage();
		config_filename = argv[i];
		argv[i] = "-dummy";
	    }
	    else if (!strcmp("-h", argv[i]) || !strcmp("-help", argv[i]))
		help();
	    else if (!strcmp("-V", argv[i]) || !strcmp("-version", argv[i])) {
		fversion(stdout);
		exit(0);
	    }
	}
    }

    /* initializations */
    init_rc(config_filename);
#ifdef USE_COOKIE
    initCookie();
#endif				/* USE_COOKIE */
    setLocalCookie();		/* setup cookie for local CGI */

    LoadHist = newHist();
    SaveHist = newHist();
    ShellHist = newHist();
    TextHist = newHist();
    URLHist = newHist();
#ifdef USE_HISTORY
    loadHistory(URLHist);
#endif				/* not USE_HISTORY */

    if (!non_null(HTTP_proxy) &&
	((p = getenv("HTTP_PROXY")) ||
	 (p = getenv("http_proxy")) || (p = getenv("HTTP_proxy")))) {
	HTTP_proxy = p;
	parseURL(p, &HTTP_proxy_parsed, NULL);
    }
#ifdef USE_GOPHER
    if (!non_null(GOPHER_proxy) &&
	((p = getenv("GOPHER_PROXY")) ||
	 (p = getenv("gopher_proxy")) || (p = getenv("GOPHER_proxy")))) {
	GOPHER_proxy = p;
	parseURL(p, &GOPHER_proxy_parsed, NULL);
    }
#endif				/* USE_GOPHER */
    if (!non_null(FTP_proxy) &&
	((p = getenv("FTP_PROXY")) ||
	 (p = getenv("ftp_proxy")) || (p = getenv("FTP_proxy")))) {
	FTP_proxy = p;
	parseURL(p, &FTP_proxy_parsed, NULL);
    }
    if (!non_null(NO_proxy) &&
	((p = getenv("NO_PROXY")) ||
	 (p = getenv("no_proxy")) || (p = getenv("NO_proxy")))) {
	NO_proxy = p;
	set_no_proxy(p);
    }

    if (!non_null(Editor) && (p = getenv("EDITOR")) != NULL)
	Editor = p;
    if (!non_null(Mailer) && (p = getenv("MAILER")) != NULL)
	Mailer = p;

    /* argument search 2 */
    i = 1;
    while (i < argc) {
	if (*argv[i] == '-') {
	    if (!strcmp("-t", argv[i])) {
		if (++i >= argc)
		    usage();
		if (atoi(argv[i]) > 0)
		    Tabstop = atoi(argv[i]);
	    }
	    else if (!strcmp("-r", argv[i]))
		ShowEffect = FALSE;
	    else if (!strcmp("-l", argv[i])) {
		if (++i >= argc)
		    usage();
		if (atoi(argv[i]) > 0)
		    PagerMax = atoi(argv[i]);
	    }
#ifdef JP_CHARSET
#ifndef DEBIAN			/* XXX: use -o kanjicode={S|J|E} */
	    else if (!strcmp("-s", argv[i]))
		DisplayCode = CODE_SJIS;
	    else if (!strcmp("-j", argv[i]))
		DisplayCode = CODE_JIS_n;
	    else if (!strcmp("-e", argv[i]))
		DisplayCode = CODE_EUC;
#endif
	    else if (!strncmp("-I", argv[i], 2)) {
		if (argv[i][2])
		    argv[i] += 2;
		else if (++i >= argc)
		    usage();
		c = str_to_code(argv[i]);
		switch (c) {
		case CODE_EUC:
		case CODE_SJIS:
		case CODE_INNER_EUC:
		    DocumentCode = c;
		    UseContentCharset = FALSE;
		    UseAutoDetect = FALSE;
		    break;
		default:
		    DocumentCode = '\0';
		    UseContentCharset = TRUE;
		    UseAutoDetect = TRUE;
		    break;
		}
	    }
	    else if (!strncmp("-O", argv[i], 2)) {
		if (argv[i][2])
		    argv[i] += 2;
		else if (++i >= argc)
		    usage();
		c = str_to_code(argv[i]);
		if (c != CODE_INNER_EUC && c != CODE_ASCII)
		    DisplayCode = c;
	    }
#endif				/* JP_CHARSET */
#ifndef KANJI_SYMBOLS
	    else if (!strcmp("-no-graph", argv[i]))
		no_graphic_char = TRUE;
#endif				/* not KANJI_SYMBOLS */
	    else if (!strcmp("-T", argv[i])) {
		if (++i >= argc)
		    usage();
		DefaultType = default_type = argv[i];
	    }
	    else if (!strcmp("-m", argv[i]))
		SearchHeader = search_header = TRUE;
	    else if (!strcmp("-v", argv[i]))
		visual_start = TRUE;
#ifdef USE_COLOR
	    else if (!strcmp("-M", argv[i]))
		useColor = FALSE;
#endif				/* USE_COLOR */
	    else if (!strcmp("-B", argv[i]))
		load_bookmark = TRUE;
	    else if (!strcmp("-bookmark", argv[i])) {
		if (++i >= argc)
		    usage();
		BookmarkFile = argv[i];
		if (BookmarkFile[0] != '~' && BookmarkFile[0] != '/') {
		    Str tmp = Strnew_charp(CurrentDir);
		    if (Strlastchar(tmp) != '/')
			Strcat_char(tmp, '/');
		    Strcat_charp(tmp, BookmarkFile);
		    BookmarkFile = cleanupName(tmp->ptr);
		}
	    }
	    else if (!strcmp("-F", argv[i]))
		RenderFrame = TRUE;
	    else if (!strcmp("-W", argv[i])) {
		if (WrapSearch) {
		    WrapSearch = FALSE;
		}
		else {
		    WrapSearch = TRUE;
		}
	    }
	    else if (!strcmp("-dump", argv[i]))
		w3m_dump = DUMP_BUFFER;
	    else if (!strcmp("-dump_source", argv[i]))
		w3m_dump = DUMP_SOURCE;
	    else if (!strcmp("-dump_head", argv[i]))
		w3m_dump = DUMP_HEAD;
	    else if (!strcmp("-dump_both", argv[i]))
		w3m_dump = (DUMP_HEAD | DUMP_SOURCE);
	    else if (!strcmp("-dump_extra", argv[i]))
		w3m_dump = (DUMP_HEAD | DUMP_SOURCE | DUMP_EXTRA);
	    else if (!strcmp("-halfdump", argv[i]))
		w3m_dump = DUMP_HALFDUMP;
	    else if (!strcmp("-halfload", argv[i])) {
		w3m_dump = 0;
		w3m_halfload = TRUE;
		DefaultType = default_type = "text/html";
	    }
	    else if (!strcmp("-backend", argv[i])) {
		w3m_backend = TRUE;
	    }
	    else if (!strcmp("-backend_batch", argv[i])) {
		w3m_backend = TRUE;
		if (++i >= argc)
		    usage();
		if (!backend_batch_commands)
		    backend_batch_commands = newTextList();
		pushText(backend_batch_commands, argv[i]);
	    }
	    else if (!strcmp("-cols", argv[i])) {
		if (++i >= argc)
		    usage();
		COLS = atoi(argv[i]);
	    }
	    else if (!strcmp("-ppc", argv[i])) {
		double ppc;
		if (++i >= argc)
		    usage();
		ppc = atof(argv[i]);
		if (ppc >= MINIMUM_PIXEL_PER_CHAR &&
		    ppc <= MAXIMUM_PIXEL_PER_CHAR) {
		    pixel_per_char = ppc;
		    set_pixel_per_char = TRUE;
		}
	    }
#ifdef USE_IMAGE
	    else if (!strcmp("-ppl", argv[i])) {
		double ppc;
		if (++i >= argc)
		    usage();
		ppc = atof(argv[i]);
		if (ppc >= MINIMUM_PIXEL_PER_CHAR &&
		    ppc <= MAXIMUM_PIXEL_PER_CHAR * 2) {
		    pixel_per_line = ppc;
		    set_pixel_per_line = TRUE;
		}
	    }
#endif
	    else if (!strcmp("-num", argv[i]))
		showLineNum = TRUE;
	    else if (!strcmp("-no-proxy", argv[i]))
		Do_not_use_proxy = TRUE;
	    else if (!strcmp("-post", argv[i])) {
		if (++i >= argc)
		    usage();
		post_file = argv[i];
	    }
	    else if (!strcmp("-header", argv[i])) {
		Str hs;
		if (++i >= argc)
		    usage();
		if ((hs = make_optional_header_string(argv[i])) != NULL) {
		    if (header_string == NULL)
			header_string = hs;
		    else
			Strcat(header_string, hs);
		}
		while (argv[i][0]) {
		    argv[i][0] = '\0';
		    argv[i]++;
		}
	    }
#ifdef USE_MOUSE
	    else if (!strcmp("-no-mouse", argv[i])) {
		use_mouse = FALSE;
	    }
#endif				/* USE_MOUSE */
#ifdef USE_COOKIE
	    else if (!strcmp("-no-cookie", argv[i])) {
		use_cookie = FALSE;
		accept_cookie = FALSE;
	    }
	    else if (!strcmp("-cookie", argv[i])) {
		use_cookie = TRUE;
		accept_cookie = TRUE;
	    }
#endif				/* USE_COOKIE */
	    else if (!strcmp("-pauth", argv[i])) {
		if (++i >= argc)
		    usage();
		proxy_auth_cookie = Strnew_m_charp("Basic ",
						   encodeB(argv[i])->ptr,
						   NULL);
		while (argv[i][0]) {
		    argv[i][0] = '\0';
		    argv[i]++;
		}
	    }
#ifdef DEBIAN
	    else if (!strcmp("-s", argv[i]))
#else
	    else if (!strcmp("-S", argv[i]))
#endif
		squeezeBlankLine = TRUE;
	    else if (!strcmp("-X", argv[i]))
		Do_not_use_ti_te = TRUE;
	    else if (!strcmp("-title", argv[i]))
		displayTitleTerm = getenv("TERM");
	    else if (!strncmp("-title=", argv[i], 7))
		displayTitleTerm = argv[i] + 7;
	    else if (!strcmp("-o", argv[i])) {
		if (++i >= argc || !strcmp(argv[i], "?")) {
		    show_params_p = 1;
		    usage();
		}
		if (!set_param_option(argv[i])) {
		    /* option set failed */
		    fprintf(stderr, "%s: bad option\n", argv[i]);
		    show_params_p = 1;
		    usage();
		}
		option_assigned = 1;
	    }
	    else if (!strcmp("-dummy", argv[i])) {
		/* do nothing */
	    }
	    else if (!strcmp("-debug", argv[i]))
		w3m_debug = TRUE;
	    else {
		usage();
	    }
	}
	else if (*argv[i] == '+') {
	    line_str = argv[i] + 1;
	}
	else {
	    load_argv[load_argc++] = argv[i];
	}
	i++;
    }

    if (option_assigned)
	sync_with_option();

#ifdef	__WATT32__
    if (w3m_debug)
	dbug_init();
    sock_init();
#endif

    FirstTab = NULL;
    LastTab = NULL;
    nTab = 0;
    CurrentTab = NULL;
    CurrentKey = -1;
    if (BookmarkFile == NULL)
	BookmarkFile = rcFile(BOOKMARK);

    if (!isatty(1) && !w3m_dump) {
	/* redirected output */
	w3m_dump = DUMP_BUFFER;
    }
    if (w3m_dump) {
	if (COLS == 0)
	    COLS = 80;
    }

#ifdef USE_BINMODE_STREAM
    setmode(fileno(stdout), O_BINARY);
#endif
    if (w3m_backend)
	backend();
    if (!w3m_dump) {
	initKeymap(TRUE);
#ifdef USE_MENU
	initMenu();
#endif				/* MENU */
	fmInit();
#ifdef SIGWINCH
	signal(SIGWINCH, resize_hook);
#else				/* not SIGWINCH */
	setlinescols();
	setupscreen();
#endif				/* not SIGWINCH */
    }
#ifdef USE_IMAGE
    else if (w3m_halfdump && displayImage)
	activeImage = TRUE;
#endif
#ifdef SIGCHLD
    signal(SIGCHLD, sig_chld);
#endif
#ifdef SIGPIPE
    signal(SIGPIPE, SigPipe);
#endif

    orig_GC_warn_proc = GC_set_warn_proc(wrap_GC_warn_proc);
    err_msg = Strnew();
    if (load_argc == 0) {
	/* no URL specified */
	if (!isatty(0)) {
	    redin = newFileStream(fdopen(dup(0), "rb"), (void (*)())pclose);
	    newbuf = openGeneralPagerBuffer(redin);
	    dup2(1, 0);
	}
	else if (load_bookmark) {
	    newbuf = loadGeneralFile(BookmarkFile, NULL, NO_REFERER, 0, NULL);
	    if (newbuf == NULL)
		Strcat_charp(err_msg, "w3m: Can't load bookmark.\n");
	}
	else if (visual_start) {
	    Str s_page;
	    s_page =
		Strnew_charp
		("<title>W3M startup page</title><center><b>Welcome to ");
	    Strcat_charp(s_page, "<a href='http://w3m.sourceforge.net/'>");
	    Strcat_m_charp(s_page,
			   "w3m</a>!<p><p>This is w3m version ",
			   w3m_version,
			   "<br>Written by <a href='mailto:aito@fw.ipsj.or.jp'>Akinori Ito</a>",
			   NULL);
#ifdef DEBIAN
	    Strcat_m_charp(s_page,
			   "<p>Debian package is maintained by <a href='mailto:ukai@debian.or.jp'>Fumitoshi UKAI</a>.",
			   "You can read <a href='file:///usr/share/doc/w3m/'>w3m documents on your local system</a>.",
			   NULL);
#endif				/* DEBIAN */
	    newbuf = loadHTMLString(s_page);
	    if (newbuf == NULL)
		Strcat_charp(err_msg, "w3m: Can't load string.\n");
	    else if (newbuf != NO_BUFFER)
		newbuf->bufferprop |= (BP_INTERNAL | BP_NO_URL);
	}
	else if ((p = getenv("HTTP_HOME")) != NULL ||
		 (p = getenv("WWW_HOME")) != NULL) {
	    newbuf = loadGeneralFile(p, NULL, NO_REFERER, 0, NULL);
	    if (newbuf == NULL)
		Strcat(err_msg, Sprintf("w3m: Can't load %s.\n", p));
	    else if (newbuf != NO_BUFFER)
		pushHashHist(URLHist, parsedURL2Str(&newbuf->currentURL)->ptr);
	}
	else {
	    if (fmInitialized)
		fmTerm();
	    usage();
	}
	if (newbuf == NULL) {
	    if (fmInitialized)
		fmTerm();
	    if (err_msg->length)
		fprintf(stderr, "%s", err_msg->ptr);
	    w3m_exit(2);
	}
	i = -1;
    }
    else {
	i = 0;
    }
    for (; i < load_argc; i++) {
	if (i >= 0) {
	    SearchHeader = search_header;
	    DefaultType = default_type;
	    if (w3m_dump == DUMP_HEAD) {
		request = New(FormList);
		request->method = FORM_METHOD_HEAD;
		newbuf =
		    loadGeneralFile(load_argv[i], NULL, NO_REFERER, 0,
				    request);
	    }
	    else {
		if (post_file && i == 0) {
		    FILE *fp;
		    Str body;
		    if (!strcmp(post_file, "-"))
			fp = stdin;
		    else
			fp = fopen(post_file, "r");
		    if (fp == NULL) {
			Strcat(err_msg,
			       Sprintf("w3m: Can't open %s.\n", post_file));
			continue;
		    }
		    body = Strfgetall(fp);
		    if (fp != stdin)
			fclose(fp);
		    request =
			newFormList(NULL, "post", NULL, NULL, NULL, NULL,
				    NULL);
		    request->body = body->ptr;
		    request->boundary = NULL;
		    request->length = body->length;
		}
		else {
		    request = NULL;
		}
		newbuf =
		    loadGeneralFile(load_argv[i], NULL, NO_REFERER, 0,
				    request);
	    }
	    if (newbuf == NULL) {
		Strcat(err_msg,
		       Sprintf("w3m: Can't load %s.\n", load_argv[i]));
		continue;
	    }
	    else if (newbuf == NO_BUFFER)
		continue;
	    switch (newbuf->real_scheme) {
#ifdef USE_NNTP
	    case SCM_NNTP:
	    case SCM_NEWS:
#endif				/* USE_NNTP */
	    case SCM_MAILTO:
		break;
	    case SCM_LOCAL:
	    case SCM_LOCAL_CGI:
		unshiftHist(LoadHist, conv_from_system(load_argv[i]));
	    default:
		pushHashHist(URLHist, parsedURL2Str(&newbuf->currentURL)->ptr);
		break;
	    }
	}
	else if (newbuf == NO_BUFFER)
	    continue;
	newbuf->search_header = search_header;
	if (CurrentTab == NULL) {
	    FirstTab = LastTab = CurrentTab = newTab();
	    nTab = 1;
	    Firstbuf = Currentbuf = newbuf;
	}
	else {
	    Currentbuf->nextBuffer = newbuf;
	    Currentbuf = newbuf;
	}
	if (w3m_dump) {
	    if (w3m_dump & DUMP_EXTRA)
		dump_extra(Currentbuf);
	    if (w3m_dump & DUMP_HEAD)
		dump_head(Currentbuf);
	    if (w3m_dump & DUMP_SOURCE)
		dump_source(Currentbuf);
	    if (w3m_dump == DUMP_BUFFER) {
		if (Currentbuf->frameset != NULL && RenderFrame)
		    rFrame();
		saveBuffer(Currentbuf, stdout);
	    }
	}
	else {
	    if (Currentbuf->frameset != NULL && RenderFrame)
		rFrame();
	    Currentbuf = newbuf;
#ifdef USE_BUFINFO
	    saveBufferInfo();
#endif
	}
    }
    if (w3m_dump) {
#ifdef USE_COOKIE
	save_cookies();
#endif				/* USE_COOKIE */
	w3m_exit(0);
    }

    if (!FirstTab || !Firstbuf || Firstbuf == NO_BUFFER) {
	if (newbuf == NO_BUFFER) {
	    if (fmInitialized)
		inputChar("Hit any key to quit w3m:");
	}
	if (fmInitialized)
	    fmTerm();
	if (err_msg->length)
	    fprintf(stderr, "%s", err_msg->ptr);
	if (newbuf == NO_BUFFER) {
#ifdef USE_COOKIE
	    save_cookies();
#endif				/* USE_COOKIE */
	    if (!err_msg->length)
		w3m_exit(0);
	}
	w3m_exit(2);
    }
    if (err_msg->length)
	disp_message_nsec(err_msg->ptr, FALSE, 1, TRUE, FALSE);

    SearchHeader = FALSE;
    DefaultType = NULL;
#ifdef JP_CHARSET
    UseContentCharset = TRUE;
    UseAutoDetect = TRUE;
#endif

    Currentbuf = Firstbuf;
    displayBuffer(Currentbuf, B_NORMAL);
    if (line_str) {
	_goLine(line_str);
    }
    onA();
    for (;;) {
	if (Currentbuf->submit) {
	    Anchor *a = Currentbuf->submit;
	    Currentbuf->submit = NULL;
	    gotoLine(Currentbuf, a->start.line);
	    Currentbuf->pos = a->start.pos;
	    _followForm(TRUE);
	}
	/* event processing */
	if (n_event_queue > 0) {
	    for (i = 0; i < n_event_queue; i++) {
		CurrentKey = -1;
		CurrentKeyData = eventQueue[i].user_data;
		CurrentCmdData = NULL;
		w3mFuncList[eventQueue[i].cmd].func();
	    }
	    n_event_queue = 0;
	}
	CurrentKeyData = NULL;
	/* get keypress event */
#ifdef USE_MOUSE
	if (use_mouse)
	    mouse_active();
#endif				/* USE_MOUSE */
#ifdef USE_ALARM
	if (alarm_status == AL_IMPLICIT) {
	    alarm_buffer = Currentbuf;
	    alarm_status = AL_IMPLICIT_DONE;
	}
	else if (alarm_status == AL_IMPLICIT_DONE
		 && alarm_buffer != Currentbuf) {
	    setAlarmEvent(0, AL_UNSET, FUNCNAME_nulcmd, NULL);
	}
	if (alarm_sec > 0) {
	    signal(SIGALRM, SigAlarm);
	    alarm(alarm_sec);
	}
#endif
#ifdef SIGWINCH
	if (need_resize_screen) {
	    need_resize_screen = FALSE;
	    resize_screen();
	}
	signal(SIGWINCH, resize_handler);
#endif
#ifdef USE_IMAGE
	if (activeImage && displayImage)
	    loadImage(IMG_FLAG_NEXT);
#endif
	c = getch();
#ifdef USE_IMAGE
	if (activeImage && displayImage)
	    loadImage(IMG_FLAG_START);
#endif
#ifdef SIGWINCH
	signal(SIGWINCH, resize_hook);
#endif
#ifdef USE_ALARM
	if (alarm_sec > 0) {
	    alarm(0);
	}
#endif
#ifdef USE_MOUSE
	if (use_mouse)
	    mouse_inactive();
#endif				/* USE_MOUSE */
	if (IS_ASCII(c)) {	/* Ascii */
	    if (((prec_num && c == '0') || '1' <= c) && (c <= '9')) {
		prec_num = prec_num * 10 + (int)(c - '0');
		if (prec_num > PREC_LIMIT)
		    prec_num = PREC_LIMIT;
	    }
	    else {
		set_buffer_environ(Currentbuf);
		keyPressEventProc((int)c);
		prec_num = 0;
	    }
	}
	prev_key = CurrentKey;
	CurrentKey = -1;
    }
}

static void
keyPressEventProc(int c)
{
    CurrentKey = c;
    w3mFuncList[(int)GlobalKeymap[c]].func();
    onA();
}

void
pushEvent(int event, void *user_data)
{
    if (n_event_queue < N_EVENT_QUEUE) {
	eventQueue[n_event_queue].cmd = event;
	eventQueue[n_event_queue].user_data = user_data;
	n_event_queue++;
    }
}

static void
dump_source(Buffer *buf)
{
    FILE *f;
    char c;
    if (buf->sourcefile == NULL)
	return;
    f = fopen(buf->sourcefile, "r");
    if (f == NULL)
	return;
    while (c = fgetc(f), !feof(f)) {
	putchar(c);
    }
    fclose(f);
}

static void
dump_head(Buffer *buf)
{
    TextListItem *ti;

    if (buf->document_header == NULL) {
	if (w3m_dump & DUMP_EXTRA)
	    printf("\n");
	return;
    }
    for (ti = buf->document_header->first; ti; ti = ti->next) {
	printf("%s", ti->ptr);
    }
    puts("");
}

static void
dump_extra(Buffer *buf)
{
    printf("W3m-current-url: %s\n", parsedURL2Str(&buf->currentURL)->ptr);
    if (buf->baseURL)
	printf("W3m-base-url: %s\n", parsedURL2Str(buf->baseURL)->ptr);
#ifdef JP_CHARSET
    printf("W3m-document-charset: %s\n", code_to_str(buf->document_code));
#endif
#ifdef USE_SSL
    if (buf->ssl_certificate) {
	Str tmp = Strnew();
	char *p;
	for (p = buf->ssl_certificate; *p; p++) {
	    Strcat_char(tmp, *p);
	    if (*p == '\n') {
		for (; *(p + 1) == '\n'; p++) ;
		if (*(p + 1))
		    Strcat_char(tmp, '\t');
	    }
	}
	if (Strlastchar(tmp) != '\n')
	    Strcat_char(tmp, '\n');
	printf("W3m-ssl-certificate: %s", tmp->ptr);
    }
#endif
}

void
nulcmd(void)
{				/* do nothing */
}

#ifdef __EMX__
void
pcmap(void)
{
    w3mFuncList[(int)PcKeymap[(int)getch()]].func();
}
#else				/* not __EMX__ */
void
pcmap(void)
{
}
#endif

void
escmap(void)
{
    char c;
    c = getch();
    if (IS_ASCII(c)) {
	CurrentKey = K_ESC | c;
	w3mFuncList[(int)EscKeymap[(int)c]].func();
    }
}

void
escbmap(void)
{
    char c;
    c = getch();

    if (IS_DIGIT(c))
	escdmap(c);
    else if (IS_ASCII(c)) {
	CurrentKey = K_ESCB | c;
	w3mFuncList[(int)EscBKeymap[(int)c]].func();
    }
}

void
escdmap(char c)
{
    int d;

    d = (int)c - (int)'0';
    c = getch();
    if (IS_DIGIT(c)) {
	d = d * 10 + (int)c - (int)'0';
	c = getch();
    }
    if (c == '~') {
	CurrentKey = K_ESCD | d;
	w3mFuncList[(int)EscDKeymap[d]].func();
    }
}

void
tmpClearBuffer(Buffer *buf)
{
    if (buf->pagerSource == NULL && writeBufferCache(buf) == 0) {
	buf->firstLine = NULL;
	buf->topLine = NULL;
	buf->currentLine = NULL;
	buf->lastLine = NULL;
    }
}

static Str currentURL(void);

void
saveBufferInfo()
{
    FILE *fp;

    if (w3m_dump)
	return;
    if ((fp = fopen(rcFile("bufinfo"), "w")) == NULL) {
	return;
    }
    fprintf(fp, "%s\n", currentURL()->ptr);
    fclose(fp);
}

static void
pushBuffer(Buffer *buf)
{
    Buffer *b;

#ifdef USE_IMAGE
    deleteImage(Currentbuf);
#endif
    if (clear_buffer)
	tmpClearBuffer(Currentbuf);
    if (Firstbuf == Currentbuf) {
	buf->nextBuffer = Firstbuf;
	Firstbuf = Currentbuf = buf;
    }
    else if ((b = prevBuffer(Firstbuf, Currentbuf)) != NULL) {
	b->nextBuffer = buf;
	buf->nextBuffer = Currentbuf;
	Currentbuf = buf;
    }
#ifdef USE_BUFINFO
    saveBufferInfo();
#endif

}

static void
delBuffer(Buffer *buf)
{
    if (buf == NULL)
	return;
    if (Currentbuf == buf)
	Currentbuf = buf->nextBuffer;
    Firstbuf = deleteBuffer(Firstbuf, buf);
    if (!Currentbuf)
	Currentbuf = Firstbuf;
}

static void
repBuffer(Buffer *oldbuf, Buffer *buf)
{
    Firstbuf = replaceBuffer(Firstbuf, oldbuf, buf);
    Currentbuf = buf;
}


MySignalHandler
intTrap(SIGNAL_ARG)
{				/* Interrupt catcher */
    LONGJMP(IntReturn, 0);
    SIGNAL_RETURN;
}

#ifdef SIGWINCH
static MySignalHandler
resize_hook(SIGNAL_ARG)
{
    need_resize_screen = TRUE;
    signal(SIGWINCH, resize_hook);
    SIGNAL_RETURN;
}

static MySignalHandler
resize_handler(SIGNAL_ARG)
{
    resize_screen();
    signal(SIGWINCH, resize_handler);
    SIGNAL_RETURN;
}

static void
resize_screen(void)
{
    setlinescols();
    setupscreen();
    if (Currentbuf)
	displayBuffer(Currentbuf, B_FORCE_REDRAW);
}
#endif				/* SIGWINCH */

#ifdef SIGPIPE
static MySignalHandler
SigPipe(SIGNAL_ARG)
{
#ifdef USE_MIGEMO
    init_migemo();
#endif
    signal(SIGPIPE, SigPipe);
    SIGNAL_RETURN;
}
#endif

/* 
 * Command functions: These functions are called with a keystroke.
 */

#define MAX(a, b)  ((a) > (b) ? (a) : (b))
#define MIN(a, b)  ((a) < (b) ? (a) : (b))

static void
nscroll(int n, int mode)
{
    Line *curtop = Currentbuf->topLine;
    int lnum, tlnum, llnum, diff_n;

    if (Currentbuf->firstLine == NULL)
	return;
    lnum = Currentbuf->currentLine->linenumber;
    Currentbuf->topLine = lineSkip(Currentbuf, curtop, n, FALSE);
    if (Currentbuf->topLine == curtop) {
	lnum += n;
	if (lnum < Currentbuf->topLine->linenumber)
	    lnum = Currentbuf->topLine->linenumber;
	else if (lnum > Currentbuf->lastLine->linenumber)
	    lnum = Currentbuf->lastLine->linenumber;
    }
    else {
	tlnum = Currentbuf->topLine->linenumber;
	llnum = Currentbuf->topLine->linenumber + LASTLINE - Currentbuf->rootY
		- 1;
#ifdef NEXTPAGE_TOPLINE
	if (nextpage_topline)
	    diff_n = 0;
	else
#endif
	    diff_n = n - (tlnum - curtop->linenumber);
	if (lnum < tlnum)
	    lnum = tlnum + diff_n;
	if (lnum > llnum)
	    lnum = llnum + diff_n;
    }
    gotoLine(Currentbuf, lnum);
    arrangeLine(Currentbuf);
    displayBuffer(Currentbuf, mode);
}

/* Move page forward */
void
pgFore(void)
{
#ifdef VI_PREC_NUM
    if (vi_prec_num)
	nscroll(searchKeyNum() * (LASTLINE - Currentbuf->rootY - 1), B_NORMAL);
    else
#endif
	nscroll(prec_num ? searchKeyNum() : searchKeyNum()
		* (LASTLINE - Currentbuf->rootY - 1),
		prec_num ? B_SCROLL : B_NORMAL);
}

/* Move page backward */
void
pgBack(void)
{
#ifdef VI_PREC_NUM
    if (vi_prec_num)
	nscroll(-searchKeyNum() * (LASTLINE - Currentbuf->rootY - 1), B_NORMAL);
    else
#endif
	nscroll(-(prec_num ? searchKeyNum() : searchKeyNum()
		* (LASTLINE - Currentbuf->rootY - 1)),
		prec_num ? B_SCROLL : B_NORMAL);
}

/* 1 line up */
void
lup1(void)
{
    nscroll(searchKeyNum(), B_SCROLL);
}

/* 1 line down */
void
ldown1(void)
{
    nscroll(-searchKeyNum(), B_SCROLL);
}

/* move cursor position to the center of screen */
void
ctrCsrV(void)
{
    int offsety;
    if (Currentbuf->firstLine == NULL)
	return;
    offsety = (LASTLINE - Currentbuf->rootY) / 2 - Currentbuf->cursorY;
    if (offsety != 0) {
#if 0
	Currentbuf->currentLine = lineSkip(Currentbuf,
					   Currentbuf->currentLine, offsety,
					   FALSE);
#endif
	Currentbuf->topLine =
	    lineSkip(Currentbuf, Currentbuf->topLine, -offsety, FALSE);
	arrangeLine(Currentbuf);
	displayBuffer(Currentbuf, B_NORMAL);
    }
}

void
ctrCsrH(void)
{
    int offsetx;
    if (Currentbuf->firstLine == NULL)
	return;
    offsetx = Currentbuf->cursorX - Currentbuf->COLS / 2;
    if (offsetx != 0) {
	columnSkip(Currentbuf, offsetx);
	arrangeCursor(Currentbuf);
	displayBuffer(Currentbuf, B_NORMAL);
    }
}

/* Redraw screen */
void
rdrwSc(void)
{
    clear();
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

static void
clear_mark(Line *l)
{
    short pos;
    if (!l)
	return;
    for (pos = 0; pos < l->len; pos++)
	l->propBuf[pos] &= ~PE_MARK;
}

/* search by regular expression */
static int
srchcore(char *str, int (*func) (Buffer *, char *))
{
    MySignalHandler(*prevtrap) ();
    volatile int i, result = SR_NOTFOUND;

    if (str != NULL && str != SearchString)
	SearchString = str;
    if (SearchString == NULL || *SearchString == '\0')
	return SR_NOTFOUND;

    prevtrap = signal(SIGINT, intTrap);
    crmode();
    if (SETJMP(IntReturn) == 0)
	for (i = 0; i < PREC_NUM; i++)
	    result = func(Currentbuf, SearchString);
    signal(SIGINT, prevtrap);
    term_raw();
    return result;
}

void
disp_srchresult(int result, char *prompt, char *str)
{
    if (str == NULL)
	str = "";
    if (result & SR_NOTFOUND)
	disp_message(Sprintf("Not found: %s", str)->ptr, FALSE);
    else if (result & SR_WRAPPED)
	disp_message(Sprintf("Search wrapped: %s", str)->ptr, FALSE);
    else if (show_srch_str)
	disp_message(Sprintf("%s%s", prompt, str)->ptr, FALSE);
}

static int
dispincsrch(int ch, Str buf, Lineprop *prop)
{
    static Buffer sbuf;
    static Line *currentLine;
    static short pos;
    char *str;
    int do_next_search = FALSE;

    if (ch == 0 && buf == NULL) {
	SAVE_BUFPOSITION(&sbuf);	/* search starting point */
	currentLine = sbuf.currentLine;
	pos = sbuf.pos;
	return -1;
    }

    str = buf->ptr;
    switch (ch) {
    case 022:			/* C-r */
	searchRoutine = backwardSearch;
	do_next_search = TRUE;
	break;
    case 023:			/* C-s */
	searchRoutine = forwardSearch;
	do_next_search = TRUE;
	break;

#ifdef USE_MIGEMO
    case 034:
	migemo_active = -migemo_active;
	goto done;
#endif

    default:
	if (ch >= 0)
	    return ch;		/* use InputKeymap */
    }

    if (do_next_search) {
	if (*str) {
	    SAVE_BUFPOSITION(&sbuf);
	    srchcore(str, searchRoutine);
	    arrangeCursor(Currentbuf);
	    if (Currentbuf->currentLine == currentLine
		&& Currentbuf->pos == pos) {
		SAVE_BUFPOSITION(&sbuf);
		srchcore(str, searchRoutine);
		arrangeCursor(Currentbuf);
	    }
	    displayBuffer(Currentbuf, B_FORCE_REDRAW);
	    clear_mark(Currentbuf->currentLine);
	    return -1;
	}
	else
	    return 020;		/* _prev completion for C-s C-s */
    }
    else if (*str) {
	RESTORE_BUFPOSITION(&sbuf);
	arrangeCursor(Currentbuf);
	srchcore(str, searchRoutine);
	arrangeCursor(Currentbuf);
	currentLine = Currentbuf->currentLine;
	pos = Currentbuf->pos;
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
    clear_mark(Currentbuf->currentLine);
#ifdef USE_MIGEMO
  done:
    while (*str++ != '\0') {
	if (migemo_active > 0)
	    *prop++ |= PE_UNDER;
	else
	    *prop++ &= ~PE_UNDER;
    }
#endif
    return -1;
}

void
isrch(int (*func) (Buffer *, char *), char *prompt)
{
    char *str;
    Buffer sbuf;
    SAVE_BUFPOSITION(&sbuf);
    dispincsrch(0, NULL, NULL);	/* initialize incremental search state */

    searchRoutine = func;
    str = inputLineHistSearch(prompt, NULL, IN_STRING, TextHist, dispincsrch);
    if (str == NULL) {
	RESTORE_BUFPOSITION(&sbuf);
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
    onA();
}

void
srch(int (*func) (Buffer *, char *), char *prompt)
{
    char *str;
    int result;

    str = inputStrHist(prompt, NULL, TextHist);
    if (str != NULL && *str == '\0')
	str = SearchString;
    if (str == NULL)
	return;
    result = srchcore(str, func);
    if (result & SR_FOUND)
	clear_mark(Currentbuf->currentLine);
    displayBuffer(Currentbuf, B_NORMAL);
    onA();
    disp_srchresult(result, prompt, str);
    searchRoutine = func;
}

/* Search regular expression forward */

void
srchfor(void)
{
    srch(forwardSearch, "Forward: ");
}

void
isrchfor(void)
{
    isrch(forwardSearch, "I-search: ");
}

/* Search regular expression backward */

void
srchbak(void)
{
    srch(backwardSearch, "Backward: ");
}

void
isrchbak(void)
{
    isrch(backwardSearch, "I-search backward: ");
}

static void
srch_nxtprv(int reverse)
{
    int result;
    /* *INDENT-OFF* */
    static int (*routine[2]) (Buffer *, char *) = {
	forwardSearch, backwardSearch
    };
    /* *INDENT-ON* */

    if (searchRoutine == NULL) {
	disp_message("No previous regular expression", TRUE);
	return;
    }
    if (reverse != 0)
	reverse = 1;
    if (searchRoutine == backwardSearch)
	reverse ^= 1;
    result = srchcore(SearchString, routine[reverse]);
    if (result & SR_FOUND)
	clear_mark(Currentbuf->currentLine);
    displayBuffer(Currentbuf, B_NORMAL);
    onA();
    disp_srchresult(result, (reverse ? "Backward: " : "Forward: "),
		    SearchString);
}

/* Search next matching */
void
srchnxt(void)
{
    srch_nxtprv(0);
}

/* Search previous matching */
void
srchprv(void)
{
    srch_nxtprv(1);
}

static void
shiftvisualpos(Buffer *buf, int shift)
{
    buf->visualpos -= shift;
    if (buf->visualpos >= buf->COLS)
	buf->visualpos = buf->COLS - 1;
    else if (buf->visualpos < 0)
	buf->visualpos = 0;
    arrangeLine(buf);
    if (buf->visualpos == -shift && buf->cursorX == 0)
	buf->visualpos = 0;
}

/* Shift screen left */
void
shiftl(void)
{
    int column;

    if (Currentbuf->firstLine == NULL)
	return;
    column = Currentbuf->currentColumn;
    columnSkip(Currentbuf, searchKeyNum() * (-Currentbuf->COLS + 1) + 1);
    shiftvisualpos(Currentbuf, Currentbuf->currentColumn - column);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* Shift screen right */
void
shiftr(void)
{
    int column;

    if (Currentbuf->firstLine == NULL)
	return;
    column = Currentbuf->currentColumn;
    columnSkip(Currentbuf, searchKeyNum() * (Currentbuf->COLS - 1) - 1);
    shiftvisualpos(Currentbuf, Currentbuf->currentColumn - column);
    displayBuffer(Currentbuf, B_NORMAL);
}

void
col1R(void)
{
    Buffer *buf = Currentbuf;
    Line *l = buf->currentLine;
    int j, column, n = searchKeyNum();

    if (l == NULL)
	return;
    for (j = 0; j < n; j++) {
	column = buf->currentColumn;
	columnSkip(Currentbuf, 1);
	if (column == buf->currentColumn)
	    break;
	shiftvisualpos(Currentbuf, 1);
    }
    displayBuffer(Currentbuf, B_NORMAL);
}

void
col1L(void)
{
    Buffer *buf = Currentbuf;
    Line *l = buf->currentLine;
    int j, n = searchKeyNum();

    if (l == NULL)
	return;
    for (j = 0; j < n; j++) {
	if (buf->currentColumn == 0)
	    break;
	columnSkip(Currentbuf, -1);
	shiftvisualpos(Currentbuf, -1);
    }
    displayBuffer(Currentbuf, B_NORMAL);
}

void
setEnv(void)
{
    char *env;
    char *var, *value;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    env = searchKeyData();
    if (env == NULL || *env == '\0' || strchr(env, '=') == NULL) {
	if (env != NULL && *env != '\0')
	    env = Sprintf("%s=", env)->ptr;
	env = inputStrHist("Set environ: ", env, TextHist);
	if (env == NULL || *env == '\0') {
	    displayBuffer(Currentbuf, B_NORMAL);
	    return;
	}
    }
    if ((value = strchr(env, '=')) != NULL && value > env) {
	var = allocStr(env, value - env);
	value++;
	set_environ(var, value);
    }
    displayBuffer(Currentbuf, B_NORMAL);
}

void
pipeBuf(void)
{
    Buffer *buf;
    char *cmd, *tmpf;
    FILE *f;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    cmd = searchKeyData();
    if (cmd == NULL || *cmd == '\0') {
	cmd = inputLineHist("Pipe buffer to: ", "", IN_COMMAND, ShellHist);
	if (cmd == NULL || *cmd == '\0') {
	    displayBuffer(Currentbuf, B_NORMAL);
	    return;
	}
    }
    tmpf = tmpfname(TMPF_DFL, NULL)->ptr;
    f = fopen(tmpf, "w");
    if (f == NULL) {
	disp_message(Sprintf("Can't save buffer to %s", cmd)->ptr, TRUE);
	return;
    }
    saveBuffer(Currentbuf, f);
    fclose(f);
    pushText(fileToDelete, tmpf);
    buf = getpipe(myExtCommand(cmd, tmpf, TRUE)->ptr);
    if (buf == NULL) {
	disp_message("Execution failed", FALSE);
    }
    else {
	buf->bufferprop |= (BP_INTERNAL | BP_NO_URL);
	if (buf->type == NULL)
	    buf->type = "text/plain";
	pushBuffer(buf);
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

/* Execute shell command and read output ac pipe. */
void
pipesh(void)
{
    Buffer *buf;
    char *cmd;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    cmd = searchKeyData();
    if (cmd == NULL || *cmd == '\0') {
	cmd = inputLineHist("(read shell[pipe])!", "", IN_COMMAND, ShellHist);
    }
    if (cmd != NULL)
	cmd = conv_to_system(cmd);
    if (cmd == NULL || *cmd == '\0') {
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    buf = getpipe(cmd);
    if (buf == NULL) {
	disp_message("Execution failed", FALSE);
    }
    else {
	buf->bufferprop |= (BP_INTERNAL | BP_NO_URL);
	if (buf->type == NULL)
	    buf->type = "text/plain";
	pushBuffer(buf);
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

/* Execute shell command and load entire output to buffer */
void
readsh(void)
{
    Buffer *buf;
    MySignalHandler(*prevtrap) ();
    char *cmd;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    cmd = searchKeyData();
    if (cmd == NULL || *cmd == '\0') {
	cmd = inputLineHist("(read shell)!", "", IN_COMMAND, ShellHist);
    }
    if (cmd != NULL)
	cmd = conv_to_system(cmd);
    if (cmd == NULL || *cmd == '\0') {
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    prevtrap = signal(SIGINT, intTrap);
    crmode();
    buf = getshell(cmd);
    signal(SIGINT, prevtrap);
    term_raw();
    if (buf == NULL) {
	disp_message("Execution failed", FALSE);
    }
    else {
	buf->bufferprop |= (BP_INTERNAL | BP_NO_URL);
	if (buf->type == NULL)
	    buf->type = "text/plain";
	pushBuffer(buf);
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

/* Execute shell command */
void
execsh(void)
{
    char *cmd;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    cmd = searchKeyData();
    if (cmd == NULL || *cmd == '\0') {
	cmd = inputLineHist("(exec shell)!", "", IN_COMMAND, ShellHist);
    }
    if (cmd != NULL)
	cmd = conv_to_system(cmd);
    if (cmd != NULL && *cmd != '\0') {
	fmTerm();
	system(cmd);
	printf("\n[Hit any key]");
	fflush(stdout);
	fmInit();
	getch();
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

/* Load file */
void
ldfile(void)
{
    char *fn;

    fn = searchKeyData();
    if (fn == NULL || *fn == '\0') {
	fn = inputFilenameHist("(Load)Filename? ", NULL, LoadHist);
    }
    if (fn != NULL)
	fn = conv_to_system(fn);
    if (fn == NULL || *fn == '\0') {
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    cmd_loadfile(fn);
}

/* Load help file */
void
ldhelp(void)
{
#ifdef USE_HELP_CGI
    char *lang;
    int n;

    lang = AcceptLang;
    n = strcspn(lang, ";, \t");
    cmd_loadURL(Sprintf("file:///$LIB/" HELP_CGI CGI_EXTENSION
			"?version=%s&lang=%s",
			Str_form_quote(Strnew_charp(w3m_version))->ptr,
			Str_form_quote(Strnew_charp_n(lang, n))->ptr)->ptr,
		NULL, NO_REFERER);
#else
    cmd_loadURL(helpFile(HELP_FILE), NULL, NO_REFERER);
#endif
}

static void
cmd_loadfile(char *fn)
{
    Buffer *buf;

    buf = loadGeneralFile(file_to_url(fn), NULL, NO_REFERER, 0, NULL);
    if (buf == NULL) {
	char *emsg = Sprintf("%s not found", conv_from_system(fn))->ptr;
	disp_err_message(emsg, FALSE);
    }
    else if (buf != NO_BUFFER) {
	pushBuffer(buf);
	if (RenderFrame && Currentbuf->frameset != NULL)
	    rFrame();
    }
    displayBuffer(Currentbuf, B_NORMAL);
}

/* Move cursor left */
static void
_movL(int n)
{
    int i, m = searchKeyNum();
    if (Currentbuf->firstLine == NULL)
	return;
    for (i = 0; i < m; i++)
	cursorLeft(Currentbuf, n);
    displayBuffer(Currentbuf, B_NORMAL);
}

void
movL(void)
{
    _movL(Currentbuf->COLS / 2);
}

void
movL1(void)
{
    _movL(1);
}

/* Move cursor downward */
static void
_movD(int n)
{
    int i, m = searchKeyNum();
    if (Currentbuf->firstLine == NULL)
	return;
    for (i = 0; i < m; i++)
	cursorDown(Currentbuf, n);
    displayBuffer(Currentbuf, B_NORMAL);
}

void
movD(void)
{
    _movD((LASTLINE - Currentbuf->rootY + 1) / 2);
}

void
movD1(void)
{
    _movD(1);
}

/* move cursor upward */
static void
_movU(int n)
{
    int i, m = searchKeyNum();
    if (Currentbuf->firstLine == NULL)
	return;
    for (i = 0; i < m; i++)
	cursorUp(Currentbuf, n);
    displayBuffer(Currentbuf, B_NORMAL);
}

void
movU(void)
{
    _movU((LASTLINE - Currentbuf->rootY + 1) / 2);
}

void
movU1(void)
{
    _movU(1);
}

/* Move cursor right */
static void
_movR(int n)
{
    int i, m = searchKeyNum();
    if (Currentbuf->firstLine == NULL)
	return;
    for (i = 0; i < m; i++)
	cursorRight(Currentbuf, n);
    displayBuffer(Currentbuf, B_NORMAL);
}

void
movR(void)
{
    _movR(Currentbuf->COLS / 2);
}

void
movR1(void)
{
    _movR(1);
}

/* movLW, movRW */
/* 
 * From: Takashi Nishimoto <g96p0935@mse.waseda.ac.jp> Date: Mon, 14 Jun
 * 1999 09:29:56 +0900 */

#define IS_WORD_CHAR(c,p) (IS_ALNUM(c) && CharType(p) == PC_ASCII)

static int
prev_nonnull_line(Line *line)
{
    Line *l;

    for (l = line; l != NULL && l->len == 0; l = l->prev) ;
    if (l == NULL || l->len == 0)
	return -1;

    Currentbuf->currentLine = l;
    if (l != line)
	Currentbuf->pos = Currentbuf->currentLine->len;
    return 0;
}

void
movLW(void)
{
    char *lb;
    Lineprop *pb;
    Line *pline;
    int ppos;
    int i, n = searchKeyNum();

    if (Currentbuf->firstLine == NULL)
	return;

    for (i = 0; i < n; i++) {
	pline = Currentbuf->currentLine;
	ppos = Currentbuf->pos;

	if (prev_nonnull_line(Currentbuf->currentLine) < 0)
	    goto end;

	while (1) {
	    lb = Currentbuf->currentLine->lineBuf;
	    pb = Currentbuf->currentLine->propBuf;
	    while (Currentbuf->pos > 0 &&
		   !IS_WORD_CHAR(lb[Currentbuf->pos - 1],
				 pb[Currentbuf->pos - 1])) {
		Currentbuf->pos--;
	    }
	    if (Currentbuf->pos > 0)
		break;
	    if (prev_nonnull_line(Currentbuf->currentLine->prev) < 0) {
		Currentbuf->currentLine = pline;
		Currentbuf->pos = ppos;
		goto end;
	    }
	    Currentbuf->pos = Currentbuf->currentLine->len;
	}

	lb = Currentbuf->currentLine->lineBuf;
	pb = Currentbuf->currentLine->propBuf;
	while (Currentbuf->pos > 0 &&
	       IS_WORD_CHAR(lb[Currentbuf->pos - 1],
			    pb[Currentbuf->pos - 1])) {
	    Currentbuf->pos--;
	}
    }
  end:
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
}

static int
next_nonnull_line(Line *line)
{
    Line *l;

    for (l = line; l != NULL && l->len == 0; l = l->next) ;

    if (l == NULL || l->len == 0)
	return -1;

    Currentbuf->currentLine = l;
    if (l != line)
	Currentbuf->pos = 0;
    return 0;
}

void
movRW(void)
{
    char *lb;
    Lineprop *pb;
    Line *pline;
    int ppos;
    int i, n = searchKeyNum();

    if (Currentbuf->firstLine == NULL)
	return;

    for (i = 0; i < n; i++) {
	pline = Currentbuf->currentLine;
	ppos = Currentbuf->pos;

	if (next_nonnull_line(Currentbuf->currentLine) < 0)
	    goto end;

	lb = Currentbuf->currentLine->lineBuf;
	pb = Currentbuf->currentLine->propBuf;

	while (lb[Currentbuf->pos] &&
	       IS_WORD_CHAR(lb[Currentbuf->pos], pb[Currentbuf->pos]))
	    Currentbuf->pos++;

	while (1) {
	    while (lb[Currentbuf->pos] &&
		   !IS_WORD_CHAR(lb[Currentbuf->pos], pb[Currentbuf->pos]))
		Currentbuf->pos++;
	    if (lb[Currentbuf->pos])
		break;
	    if (next_nonnull_line(Currentbuf->currentLine->next) < 0) {
		Currentbuf->currentLine = pline;
		Currentbuf->pos = ppos;
		goto end;
	    }
	    Currentbuf->pos = 0;
	    lb = Currentbuf->currentLine->lineBuf;
	    pb = Currentbuf->currentLine->propBuf;
	}
    }
  end:
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* Question and Quit */
void
qquitfm(void)
{
    char *ans;
    if (!confirm_on_quit)
	quitfm();
    ans = inputChar("Do you want to exit w3m? (y/n)");
    if (ans && tolower(*ans) == 'y')
	quitfm();
    displayBuffer(Currentbuf, B_NORMAL);
}

/* Quit */
void
quitfm(void)
{
    term_title("");		/* XXX */
#ifdef USE_IMAGE
    if (activeImage)
	termImage();
#endif
    fmTerm();
#ifdef USE_COOKIE
    save_cookies();
#endif				/* USE_COOKIE */
#ifdef USE_HISTORY
    if (SaveURLHist)
	saveHistory(URLHist, URLHistSize);
#endif				/* USE_HISTORY */
    w3m_exit(0);
}

/* Select buffer */
void
selBuf(void)
{
    Buffer *buf;
    int ok;
    char cmd;

    ok = FALSE;
    do {
	buf = selectBuffer(Firstbuf, Currentbuf, &cmd);
	switch (cmd) {
	case 'B':
	    ok = TRUE;
	    break;
	case '\n':
	case ' ':
	    Currentbuf = buf;
	    ok = TRUE;
	    break;
	case 'D':
	    delBuffer(buf);
	    if (Firstbuf == NULL) {
		/* No more buffer */
		Firstbuf = nullBuffer();
		Currentbuf = Firstbuf;
	    }
	    break;
	case 'q':
	    qquitfm();
	    break;
	case 'Q':
	    quitfm();
	    break;
	}
    } while (!ok);

    for (buf = Firstbuf; buf != NULL; buf = buf->nextBuffer) {
	if (buf == Currentbuf)
	    continue;
#ifdef USE_IMAGE
	deleteImage(buf);
#endif
	if (clear_buffer)
	    tmpClearBuffer(buf);
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

/* Suspend (on BSD), or run interactive shell (on SysV) */
void
susp(void)
{
#ifndef SIGSTOP
    char *shell;
#endif				/* not SIGSTOP */
    move(LASTLINE, 0);
    clrtoeolx();
    refresh();
    fmTerm();
#ifndef SIGSTOP
    shell = getenv("SHELL");
    if (shell == NULL)
	shell = "/bin/sh";
    system(shell);
#else				/* SIGSTOP */
    kill((pid_t) 0, SIGSTOP);
#endif				/* SIGSTOP */
    fmInit();
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

/* Go to specified line */
static void
_goLine(char *l)
{
    if (l == NULL || *l == '\0' || Currentbuf->currentLine == NULL) {
	displayBuffer(Currentbuf, B_FORCE_REDRAW);
	return;
    }
    Currentbuf->pos = 0;
    if (((*l == '^') || (*l == '$')) && prec_num) {
	gotoRealLine(Currentbuf, prec_num);
    }
    else if (*l == '^') {
	Currentbuf->topLine = Currentbuf->currentLine = Currentbuf->firstLine;
    }
    else if (*l == '$') {
	Currentbuf->topLine =
	    lineSkip(Currentbuf, Currentbuf->lastLine,
		     -(LASTLINE - Currentbuf->rootY + 1) / 2, TRUE);
	Currentbuf->currentLine = Currentbuf->lastLine;
    }
    else
	gotoRealLine(Currentbuf, atoi(l));
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

void
goLine(void)
{
    if (prec_num)
	_goLine("^");
    else
	_goLine(inputStr("Goto line: ", ""));
}

void
goLineF(void)
{
    _goLine("^");
}

void
goLineL(void)
{
    _goLine("$");
}

/* Go to the beginning of the line */
void
linbeg(void)
{
    if (Currentbuf->firstLine == NULL)
	return;
    Currentbuf->pos = 0;
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* Go to the bottom of the line */
void
linend(void)
{
    if (Currentbuf->firstLine == NULL)
	return;
    Currentbuf->pos = Currentbuf->currentLine->len - 1;
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* Run editor on the current buffer */
void
editBf(void)
{
    char *fn = Currentbuf->filename;
    Buffer *buf, *fbuf = NULL, sbuf;
#ifdef JP_CHARSET
    char old_code;
#endif
    Str cmd;

    if (fn == NULL || Currentbuf->pagerSource != NULL ||	/* Behaving as a pager */
	(Currentbuf->type == NULL && Currentbuf->edit == NULL) ||	/* Reading shell */
	Currentbuf->real_scheme != SCM_LOCAL || !strcmp(Currentbuf->currentURL.file, "-") ||	/* file is std input  */
	Currentbuf->bufferprop & BP_FRAME) {	/* Frame */
	disp_err_message("Can't edit other than local file", TRUE);
	return;
    }
    if (Currentbuf->frameset != NULL)
	fbuf = Currentbuf->linkBuffer[LB_FRAME];
    copyBuffer(&sbuf, Currentbuf);
    if (Currentbuf->edit)
	cmd = unquote_mailcap(Currentbuf->edit, Currentbuf->real_type, fn,
			      checkHeader(Currentbuf, "Content-Type:"), NULL);
    else
	cmd = myEditor(Editor, shell_quote(fn), CUR_LINENUMBER(Currentbuf));
    fmTerm();
    system(cmd->ptr);
    fmInit();

#ifdef JP_CHARSET
    old_code = DocumentCode;
    DocumentCode = Currentbuf->document_code;
#endif
    SearchHeader = Currentbuf->search_header;
    DefaultType = Currentbuf->real_type;
    buf = loadGeneralFile(file_to_url(fn), NULL, NO_REFERER, 0, NULL);
#ifdef JP_CHARSET
    DocumentCode = old_code;
#endif
    SearchHeader = FALSE;
    DefaultType = NULL;

    if (buf == NULL) {
	disp_err_message("Re-loading failed", FALSE);
	buf = nullBuffer();
    }
    else if (buf == NO_BUFFER) {
	buf = nullBuffer();
    }
    if (fbuf != NULL)
	Firstbuf = deleteBuffer(Firstbuf, fbuf);
    repBuffer(Currentbuf, buf);
    if ((buf->type != NULL) && (sbuf.type != NULL) &&
	((!strcasecmp(buf->type, "text/plain") &&
	  !strcasecmp(sbuf.type, "text/html")) ||
	 (!strcasecmp(buf->type, "text/html") &&
	  !strcasecmp(sbuf.type, "text/plain")))) {
	vwSrc();
	if (Currentbuf != buf)
	    Firstbuf = deleteBuffer(Firstbuf, buf);
    }
    Currentbuf->search_header = sbuf.search_header;
    if (Currentbuf->firstLine)
	restorePosition(Currentbuf, &sbuf);
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

/* Run editor on the current screen */
void
editScr(void)
{
    char *tmpf;
    FILE *f;

    tmpf = tmpfname(TMPF_DFL, NULL)->ptr;
    f = fopen(tmpf, "w");
    if (f == NULL) {
	disp_err_message(Sprintf("Can't open %s", tmpf)->ptr, TRUE);
	return;
    }
    saveBuffer(Currentbuf, f);
    fclose(f);
    fmTerm();
    system(myEditor(Editor, tmpf, CUR_LINENUMBER(Currentbuf))->ptr);
    fmInit();
    unlink(tmpf);
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

#ifdef USE_MARK

/* Set / unset mark */
void
_mark(void)
{
    Line *l;
    if (!use_mark)
	return;
    if (Currentbuf->firstLine == NULL)
	return;
    l = Currentbuf->currentLine;
    l->propBuf[Currentbuf->pos] ^= PE_MARK;
    redrawLine(Currentbuf, l, l->linenumber - Currentbuf->topLine->linenumber
	       + Currentbuf->rootY);
}

/* Go to next mark */
void
nextMk(void)
{
    Line *l;
    int i;

    if (!use_mark)
	return;
    if (Currentbuf->firstLine == NULL)
	return;
    i = Currentbuf->pos + 1;
    l = Currentbuf->currentLine;
    if (i >= l->len) {
	i = 0;
	l = l->next;
    }
    while (l != NULL) {
	for (; i < l->len; i++) {
	    if (l->propBuf[i] & PE_MARK) {
		Currentbuf->currentLine = l;
		Currentbuf->pos = i;
		arrangeCursor(Currentbuf);
		displayBuffer(Currentbuf, B_NORMAL);
		return;
	    }
	}
	l = l->next;
	i = 0;
    }
    disp_message("No mark exist after here", TRUE);
}

/* Go to previous mark */
void
prevMk(void)
{
    Line *l;
    int i;

    if (!use_mark)
	return;
    if (Currentbuf->firstLine == NULL)
	return;
    i = Currentbuf->pos - 1;
    l = Currentbuf->currentLine;
    if (i < 0) {
	l = l->prev;
	if (l != NULL)
	    i = l->len - 1;
    }
    while (l != NULL) {
	for (; i >= 0; i--) {
	    if (l->propBuf[i] & PE_MARK) {
		Currentbuf->currentLine = l;
		Currentbuf->pos = i;
		arrangeCursor(Currentbuf);
		displayBuffer(Currentbuf, B_NORMAL);
		return;
	    }
	}
	l = l->prev;
	if (l != NULL)
	    i = l->len - 1;
    }
    disp_message("No mark exist before here", TRUE);
}

/* Mark place to which the regular expression matches */
void
reMark(void)
{
    Line *l;
    char *str;
    char *p, *p1, *p2;

    if (!use_mark)
	return;
    str = inputStrHist("(Mark)Regexp: ", MarkString, TextHist);
    if (str == NULL || *str == '\0') {
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    if ((p = regexCompile(str, 1)) != NULL) {
	disp_message(p, TRUE);
	return;
    }
    MarkString = str;
    for (l = Currentbuf->firstLine; l != NULL; l = l->next) {
	p = l->lineBuf;
	for (;;) {
	    if (regexMatch(p, &l->lineBuf[l->len] - p, p == l->lineBuf) == 1) {
		matchedPosition(&p1, &p2);
		l->propBuf[p1 - l->lineBuf] |= PE_MARK;
		p = p2;
	    }
	    else
		break;
	}
    }

    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}
#endif				/* USE_MARK */

static Buffer *
loadNormalBuf(Buffer *buf, int renderframe)
{
    pushBuffer(buf);
    if (renderframe && RenderFrame && Currentbuf->frameset != NULL)
	rFrame();
    return buf;
}

static Buffer *
loadLink(char *url, char *target, char *referer, FormList *request)
{
    Buffer *buf, *nfbuf;
    union frameset_element *f_element = NULL;
    int flag = 0;
    ParsedURL *base, pu;

    message(Sprintf("loading %s", url)->ptr, 0, 0);
    refresh();

    base = baseURL(Currentbuf);
    if (base == NULL ||
	base->scheme == SCM_LOCAL || base->scheme == SCM_LOCAL_CGI)
	referer = NO_REFERER;
    if (referer == NULL)
	referer = parsedURL2Str(&Currentbuf->currentURL)->ptr;
    buf = loadGeneralFile(url, baseURL(Currentbuf), referer, flag, request);
    if (buf == NULL) {
	char *emsg = Sprintf("Can't load %s", url)->ptr;
	disp_err_message(emsg, FALSE);
	return NULL;
    }

    parseURL2(url, &pu, base);
    pushHashHist(URLHist, parsedURL2Str(&pu)->ptr);

    if (buf == NO_BUFFER) {
	return NULL;
    }
    if (!on_target)		/* open link as an indivisual page */
	return loadNormalBuf(buf, TRUE);

    if (do_download)		/* download (thus no need to render frame) */
	return loadNormalBuf(buf, FALSE);

    if (target == NULL ||	/* no target specified (that means this page is not a frame page) */
	!strcmp(target, "_top") ||	/* this link is specified to be opened as an indivisual * page */
	!(Currentbuf->bufferprop & BP_FRAME)	/* This page is not a frame page */
	) {
	return loadNormalBuf(buf, TRUE);
    }
    nfbuf = Currentbuf->linkBuffer[LB_N_FRAME];
    if (nfbuf == NULL) {
	/* original page (that contains <frameset> tag) doesn't exist */
	return loadNormalBuf(buf, TRUE);
    }

    f_element = search_frame(nfbuf->frameset, target);
    if (f_element == NULL) {
	/* specified target doesn't exist in this frameset */
	return loadNormalBuf(buf, TRUE);
    }

    /* frame page */

    /* stack current frameset */
    pushFrameTree(&(nfbuf->frameQ), copyFrameSet(nfbuf->frameset), Currentbuf);
    /* delete frame view buffer */
    delBuffer(Currentbuf);
    Currentbuf = nfbuf;
    /* nfbuf->frameset = copyFrameSet(nfbuf->frameset); */
    resetFrameElement(f_element, buf, referer, request);
    discardBuffer(buf);
    rFrame();
    {
	Anchor *al = NULL;
	char *label = pu.label;

	if (label && f_element->element->attr == F_BODY) {
	    al = searchAnchor(f_element->body->nameList, label);
	}
	if (!al) {
	    label = Strnew_m_charp("_", target, NULL)->ptr;
	    al = searchURLLabel(Currentbuf, label);
	}
	if (al) {
	    gotoLine(Currentbuf, al->start.line);
#ifdef LABEL_TOPLINE
	    if (label_topline)
		Currentbuf->topLine = lineSkip(Currentbuf, Currentbuf->topLine,
					       Currentbuf->currentLine->
					       linenumber -
					       Currentbuf->topLine->linenumber,
					       FALSE);
#endif
	    Currentbuf->pos = al->start.pos;
	    arrangeCursor(Currentbuf);
	}
    }
    displayBuffer(Currentbuf, B_NORMAL);
    return buf;
}

static void
gotoLabel(char *label)
{
    Buffer *buf;
    Anchor *al;
    int i;

    al = searchURLLabel(Currentbuf, label);
    if (al == NULL) {
	disp_message(Sprintf("%s is not found", label)->ptr, TRUE);
	return;
    }
    buf = newBuffer(Currentbuf->width);
    copyBuffer(buf, Currentbuf);
    for (i = 0; i < MAX_LB; i++)
	buf->linkBuffer[i] = NULL;
    buf->currentURL.label = allocStr(label, -1);
    pushHashHist(URLHist, parsedURL2Str(&buf->currentURL)->ptr);
    (*buf->clone)++;
    pushBuffer(buf);
    gotoLine(Currentbuf, al->start.line);
#ifdef LABEL_TOPLINE
    if (label_topline)
	Currentbuf->topLine = lineSkip(Currentbuf, Currentbuf->topLine,
				       Currentbuf->currentLine->linenumber
				       - Currentbuf->topLine->linenumber,
				       FALSE);
#endif
    Currentbuf->pos = al->start.pos;
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
    return;
}

/* follow HREF link */
void
followA(void)
{
    Line *l;
    Anchor *a;
    ParsedURL u;
#ifdef USE_IMAGE
    int x = 0, y = 0, map = 0;
#endif
    char *url;

    if (Currentbuf->firstLine == NULL)
	return;
    l = Currentbuf->currentLine;

#ifdef USE_IMAGE
    a = retrieveCurrentImg(Currentbuf);
    if (a && a->image && a->image->map) {
	_followForm(FALSE);
	return;
    }
    if (a && a->image && a->image->ismap) {
	getMapXY(Currentbuf, retrieveCurrentImg(Currentbuf), &x, &y);
	map = 1;
    }
#endif
    a = retrieveCurrentAnchor(Currentbuf);
    if (a == NULL) {
	_followForm(FALSE);
	return;
    }
    if (*a->url == '#') {	/* index within this buffer */
	gotoLabel(a->url + 1);
	return;
    }
    parseURL2(a->url, &u, baseURL(Currentbuf));
    if (Strcmp(parsedURL2Str(&u), parsedURL2Str(&Currentbuf->currentURL)) == 0) {
	/* index within this buffer */
	if (u.label) {
	    gotoLabel(u.label);
	    return;
	}
    }
    if (!strncasecmp(a->url, "mailto:", 7)
#ifdef USE_W3MMAILER
	&& non_null(Mailer) && strchr(a->url, '?') == NULL
#endif
	) {
	/* invoke external mailer */
	Str to = Strnew_charp(a->url + 7);
#ifndef USE_W3MMAILER
	char *pos;
	if (!non_null(Mailer)) {
	    disp_err_message("no mailer is specified", TRUE);
	    return;
	}
	if ((pos = strchr(to->ptr, '?')) != NULL)
	    Strtruncate(to, pos - to->ptr);
#endif
	fmTerm();
	system(myExtCommand(Mailer, shell_quote(url_unquote(to->ptr)),
			    FALSE)->ptr);
	fmInit();
	displayBuffer(Currentbuf, B_FORCE_REDRAW);
	pushHashHist(URLHist, a->url);
	return;
    }
#ifdef USE_NNTP
    else if (!strncasecmp(a->url, "news:", 5) && strchr(a->url, '@') == NULL) {
	/* news:newsgroup is not supported */
	disp_err_message("news:newsgroup_name is not supported", TRUE);
	return;
    }
#endif				/* USE_NNTP */
    url = a->url;
#ifdef USE_IMAGE
    if (map)
	url = Sprintf("%s?%d,%d", a->url, x, y)->ptr;
#endif

    if (check_target && open_tab_blank && a->target &&
	(!strcasecmp(a->target, "_new") || !strcasecmp(a->target, "_blank"))) {
	Buffer *buf;

	_newT();
	buf = Currentbuf;
	loadLink(url, a->target, a->referer, NULL);
	if (buf != Currentbuf)
	    delBuffer(buf);
	else
	    deleteTab(CurrentTab);
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    loadLink(url, a->target, a->referer, NULL);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* follow HREF link in the buffer */
void
bufferA(void)
{
    on_target = FALSE;
    followA();
    on_target = TRUE;
}

/* view inline image */
void
followI(void)
{
    Line *l;
    Anchor *a;
    Buffer *buf;

    if (Currentbuf->firstLine == NULL)
	return;
    l = Currentbuf->currentLine;

    a = retrieveCurrentImg(Currentbuf);
    if (a == NULL)
	return;
    message(Sprintf("loading %s", a->url)->ptr, 0, 0);
    refresh();
    buf = loadGeneralFile(a->url, baseURL(Currentbuf), NULL, 0, NULL);
    if (buf == NULL) {
	char *emsg = Sprintf("Can't load %s", a->url)->ptr;
	disp_err_message(emsg, FALSE);
    }
    else if (buf != NO_BUFFER) {
	pushBuffer(buf);
    }
    displayBuffer(Currentbuf, B_NORMAL);
}

static FormItemList *
save_submit_formlist(FormItemList *src)
{
    FormList *list;
    FormList *srclist;
    FormItemList *srcitem;
    FormItemList *item;
    FormItemList *ret = NULL;
#ifdef MENU_SELECT
    FormSelectOptionItem *opt;
    FormSelectOptionItem *curopt;
    FormSelectOptionItem *srcopt;
#endif				/* MENU_SELECT */

    if (src == NULL)
	return NULL;
    srclist = src->parent;
    list = New(FormList);
    list->method = srclist->method;
    list->action = Strdup(srclist->action);
    list->charset = srclist->charset;
    list->enctype = srclist->enctype;
    list->nitems = srclist->nitems;
    list->body = srclist->body;
    list->boundary = srclist->boundary;
    list->length = srclist->length;

    for (srcitem = srclist->item; srcitem; srcitem = srcitem->next) {
	item = New(FormItemList);
	item->type = srcitem->type;
	item->name = Strdup(srcitem->name);
	item->value = Strdup(srcitem->value);
	item->checked = srcitem->checked;
	item->accept = srcitem->accept;
	item->size = srcitem->size;
	item->rows = srcitem->rows;
	item->maxlength = srcitem->maxlength;
	item->readonly = srcitem->readonly;
#ifdef MENU_SELECT
	opt = curopt = NULL;
	for (srcopt = srcitem->select_option; srcopt; srcopt = srcopt->next) {
	    if (!srcopt->checked)
		continue;
	    opt = New(FormSelectOptionItem);
	    opt->value = Strdup(srcopt->value);
	    opt->label = Strdup(srcopt->label);
	    opt->checked = srcopt->checked;
	    if (item->select_option == NULL) {
		item->select_option = curopt = opt;
	    }
	    else {
		curopt->next = opt;
		curopt = curopt->next;
	    }
	}
	item->select_option = opt;
	if (srcitem->label)
	    item->label = Strdup(srcitem->label);
#endif				/* MENU_SELECT */
	item->parent = list;
	item->next = NULL;

	if (list->lastitem == NULL) {
	    list->item = list->lastitem = item;
	}
	else {
	    list->lastitem->next = item;
	    list->lastitem = item;
	}

	if (srcitem == src)
	    ret = item;
    }

    return ret;
}

#ifdef JP_CHARSET
static Str
conv_form_encoding(Str val, FormItemList *fi, Buffer *buf)
{
    return conv_str(val, InnerCode, fi->parent->charset ? fi->parent->charset
		    : (buf->document_code ? buf->document_code : CODE_EUC));
}
#else
#define conv_form_encoding(val, fi, buf) (val)
#endif

static void
query_from_followform(Str *query, FormItemList *fi, int multipart)
{
    FormItemList *f2;
    FILE *body = NULL;

    if (multipart) {
	*query = tmpfname(TMPF_DFL, NULL);
	body = fopen((*query)->ptr, "w");
	if (body == NULL) {
	    return;
	}
	fi->parent->body = (*query)->ptr;
	fi->parent->boundary =
	    Sprintf("------------------------------%d%ld%ld%ld", getpid(),
		    fi->parent, fi->parent->body, fi->parent->boundary)->ptr;
    }
    *query = Strnew();
    for (f2 = fi->parent->item; f2; f2 = f2->next) {
	if (f2->name == NULL)
	    continue;
	/* <ISINDEX> is translated into single text form */
	if (f2->name->length == 0 &&
	    (multipart || f2->type != FORM_INPUT_TEXT))
	    continue;
	switch (f2->type) {
	case FORM_INPUT_RESET:
	    /* do nothing */
	    continue;
	case FORM_INPUT_SUBMIT:
	case FORM_INPUT_IMAGE:
	    if (f2 != fi || f2->value == NULL)
		continue;
	    break;
	case FORM_INPUT_RADIO:
	case FORM_INPUT_CHECKBOX:
	    if (!f2->checked)
		continue;
	}
	if (multipart) {
	    if (f2->type == FORM_INPUT_IMAGE) {
		int x = 0, y = 0;
#ifdef USE_IMAGE
		getMapXY(Currentbuf, retrieveCurrentImg(Currentbuf), &x, &y);
#endif
		*query = Strdup(conv_form_encoding(f2->name, fi, Currentbuf));
		Strcat_charp(*query, ".x");
		form_write_data(body, fi->parent->boundary, (*query)->ptr,
				Sprintf("%d", x)->ptr);
		*query = Strdup(conv_form_encoding(f2->name, fi, Currentbuf));
		Strcat_charp(*query, ".y");
		form_write_data(body, fi->parent->boundary, (*query)->ptr,
				Sprintf("%d", y)->ptr);
	    }
	    else if (f2->name && f2->name->length > 0 && f2->value != NULL) {
		/* not IMAGE */
		*query = conv_form_encoding(f2->value, fi, Currentbuf);
		if (f2->type == FORM_INPUT_FILE)
		    form_write_from_file(body, fi->parent->boundary,
					 conv_form_encoding(f2->name, fi,
							    Currentbuf)->ptr,
					 (*query)->ptr,
					 Str_conv_to_system(f2->value)->ptr);
		else
		    form_write_data(body, fi->parent->boundary,
				    conv_form_encoding(f2->name, fi,
						       Currentbuf)->ptr,
				    (*query)->ptr);
	    }
	}
	else {
	    /* not multipart */
	    if (f2->type == FORM_INPUT_IMAGE) {
		int x = 0, y = 0;
#ifdef USE_IMAGE
		getMapXY(Currentbuf, retrieveCurrentImg(Currentbuf), &x, &y);
#endif
		Strcat(*query,
		       Str_form_quote(conv_form_encoding
				      (f2->name, fi, Currentbuf)));
		Strcat(*query, Sprintf(".x=%d&", x));
		Strcat(*query,
		       Str_form_quote(conv_form_encoding
				      (f2->name, fi, Currentbuf)));
		Strcat(*query, Sprintf(".y=%d", y));
	    }
	    else {
		/* not IMAGE */
		if (f2->name && f2->name->length > 0) {
		    Strcat(*query,
			   Str_form_quote(conv_form_encoding
					  (f2->name, fi, Currentbuf)));
		    Strcat_char(*query, '=');
		}
		if (f2->value != NULL) {
		    if (fi->parent->method == FORM_METHOD_INTERNAL)
			Strcat(*query, Str_form_quote(f2->value));
		    else {
			Strcat(*query,
			       Str_form_quote(conv_form_encoding
					      (f2->value, fi, Currentbuf)));
		    }
		}
	    }
	    if (f2->next)
		Strcat_char(*query, '&');
	}
    }
    if (multipart) {
	fprintf(body, "--%s--\r\n", fi->parent->boundary);
	fclose(body);
    }
    else {
	/* remove trailing & */
	while (Strlastchar(*query) == '&')
	    Strshrink(*query, 1);
    }
}

/* submit form */
void
submitForm(void)
{
    _followForm(TRUE);
}

/* process form */
void
followForm(void)
{
    _followForm(FALSE);
}

static void
_followForm(int submit)
{
    Line *l;
    Anchor *a, *a2;
    char *p;
    FormItemList *fi, *f2;
    Str tmp, tmp2;
    int multipart = 0, i;

    if (Currentbuf->firstLine == NULL)
	return;
    l = Currentbuf->currentLine;

    a = retrieveCurrentForm(Currentbuf);
    if (a == NULL)
	return;
    fi = (FormItemList *)a->url;
    switch (fi->type) {
    case FORM_INPUT_TEXT:
	if (submit)
	    goto do_submit;
	if (fi->readonly)
	    disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE);
	p = inputStrHist("TEXT:", fi->value ? fi->value->ptr : NULL, TextHist);
	if (p == NULL || fi->readonly)
	    return;
	fi->value = Strnew_charp(p);
	formUpdateBuffer(a, Currentbuf, fi);
	if (fi->accept || fi->parent->nitems == 1)
	    goto do_submit;
	break;
    case FORM_INPUT_FILE:
	if (submit)
	    goto do_submit;
	if (fi->readonly)
	    disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE);
	p = inputFilenameHist("Filename:", fi->value ? fi->value->ptr : NULL,
			      NULL);
	if (p == NULL || fi->readonly)
	    return;
	fi->value = Strnew_charp(p);
	formUpdateBuffer(a, Currentbuf, fi);
	if (fi->accept || fi->parent->nitems == 1)
	    goto do_submit;
	break;
    case FORM_INPUT_PASSWORD:
	if (submit)
	    goto do_submit;
	if (fi->readonly) {
	    disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE);
	    return;
	}
	p = inputLine("TEXT:", fi->value ? fi->value->ptr : NULL, IN_PASSWORD);
	if (p == NULL)
	    return;
	fi->value = Strnew_charp(p);
	formUpdateBuffer(a, Currentbuf, fi);
	if (fi->accept)
	    goto do_submit;
	break;
    case FORM_TEXTAREA:
	if (submit)
	    goto do_submit;
	if (fi->readonly)
	    disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE);
	input_textarea(fi);
	formUpdateBuffer(a, Currentbuf, fi);
	break;
    case FORM_INPUT_RADIO:
	if (submit)
	    goto do_submit;
	if (fi->readonly) {
	    disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE);
	    return;
	}
	formRecheckRadio(a, Currentbuf, fi);
	break;
    case FORM_INPUT_CHECKBOX:
	if (submit)
	    goto do_submit;
	if (fi->readonly) {
	    disp_message_nsec("Read only field!", FALSE, 1, TRUE, FALSE);
	    return;
	}
	fi->checked = !fi->checked;
	formUpdateBuffer(a, Currentbuf, fi);
	break;
#ifdef MENU_SELECT
    case FORM_SELECT:
	if (submit)
	    goto do_submit;
	if (!formChooseOptionByMenu(fi,
				    Currentbuf->cursorX - Currentbuf->pos +
				    a->start.pos + Currentbuf->rootX,
				    Currentbuf->cursorY + Currentbuf->rootY))
	    break;
	formUpdateBuffer(a, Currentbuf, fi);
	if (fi->parent->nitems == 1)
	    goto do_submit;
	break;
#endif				/* MENU_SELECT */
    case FORM_INPUT_IMAGE:
    case FORM_INPUT_SUBMIT:
    case FORM_INPUT_BUTTON:
      do_submit:
	tmp = Strnew();
	tmp2 = Strnew();
	multipart = (fi->parent->method == FORM_METHOD_POST &&
		     fi->parent->enctype == FORM_ENCTYPE_MULTIPART);
	query_from_followform(&tmp, fi, multipart);

	tmp2 = Strdup(fi->parent->action);
	if (!Strcmp_charp(tmp2, "!CURRENT_URL!")) {
	    /* It means "current URL" */
	    tmp2 = parsedURL2Str(&Currentbuf->currentURL);
	    if ((p = strchr(tmp2->ptr, '?')) != NULL)
		Strshrink(tmp2, (tmp2->ptr + tmp2->length) - p);
	}

	if (fi->parent->method == FORM_METHOD_GET) {
	    Strcat_charp(tmp2, "?");
	    Strcat(tmp2, tmp);
	    loadLink(tmp2->ptr, a->target, NULL, NULL);
	}
	else if (fi->parent->method == FORM_METHOD_POST) {
	    Buffer *buf;
	    if (multipart) {
		struct stat st;
		stat(fi->parent->body, &st);
		fi->parent->length = st.st_size;
	    }
	    else {
		fi->parent->body = tmp->ptr;
		fi->parent->length = tmp->length;
	    }
	    buf = loadLink(tmp2->ptr, a->target, NULL, fi->parent);
	    if (multipart) {
		unlink(fi->parent->body);
	    }
	    if (buf && !(buf->bufferprop & BP_REDIRECTED)) {	/* buf must be Currentbuf */
		/* BP_REDIRECTED means that the buffer is obtained through
		 * Location: header. In this case, buf->form_submit must not be set
		 * because the page is not loaded by POST method but GET method.
		 */
		buf->form_submit = save_submit_formlist(fi);
	    }
	}
	else if ((fi->parent->method == FORM_METHOD_INTERNAL && (!Strcmp_charp(fi->parent->action, "map") || !Strcmp_charp(fi->parent->action, "none"))) || Currentbuf->bufferprop & BP_INTERNAL) {	/* internal */
	    do_internal(tmp2->ptr, tmp->ptr);
	}
	else {
	    disp_err_message("Can't send form because of illegal method.",
			     FALSE);
	}
	break;
    case FORM_INPUT_RESET:
	for (i = 0; i < Currentbuf->formitem->nanchor; i++) {
	    a2 = &Currentbuf->formitem->anchors[i];
	    f2 = (FormItemList *)a2->url;
	    if (f2->parent == fi->parent &&
		f2->name && f2->value &&
		f2->type != FORM_INPUT_SUBMIT &&
		f2->type != FORM_INPUT_HIDDEN &&
		f2->type != FORM_INPUT_RESET) {
		f2->value = f2->init_value;
		f2->checked = f2->init_checked;
#ifdef MENU_SELECT
		f2->label = f2->init_label;
		f2->selected = f2->init_selected;
#endif				/* MENU_SELECT */
		formUpdateBuffer(a2, Currentbuf, f2);
	    }
	}
	break;
    case FORM_INPUT_HIDDEN:
    default:
	break;
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

static void
drawAnchorCursor0(Buffer *buf, int hseq, int prevhseq, int tline, int eline,
		  int active)
{
    int i, j;
    Line *l;
    Anchor *an;

    l = buf->topLine;
    for (j = 0; j < buf->href->nanchor; j++) {
	an = &buf->href->anchors[j];
	if (an->start.line < tline)
	    continue;
	if (an->start.line >= eline)
	    return;
	for (;; l = l->next) {
	    if (l == NULL)
		return;
	    if (l->linenumber == an->start.line)
		break;
	}
	if (hseq >= 0 && an->hseq == hseq) {
	    for (i = an->start.pos; i < an->end.pos; i++) {
		if (l->propBuf[i] & (PE_IMAGE | PE_ANCHOR | PE_FORM)) {
		    if (active)
			l->propBuf[i] |= PE_ACTIVE;
		    else
			l->propBuf[i] &= ~PE_ACTIVE;
		}
	    }
	    if (active)
		redrawLineRegion(buf, l, l->linenumber - tline + buf->rootY,
				 an->start.pos, an->end.pos);
	}
	else if (prevhseq >= 0 && an->hseq == prevhseq) {
	    if (active)
		redrawLineRegion(buf, l, l->linenumber - tline + buf->rootY,
				 an->start.pos, an->end.pos);
	}
    }
}


void
drawAnchorCursor(Buffer *buf)
{
    Anchor *an;
    int hseq, prevhseq;
    int tline, eline;

    if (buf->firstLine == NULL)
	return;
    if (buf->href == NULL)
	return;

    an = retrieveCurrentAnchor(buf);
    if (an != NULL)
	hseq = an->hseq;
    else
	hseq = -1;
    tline = buf->topLine->linenumber;
    eline = tline + LASTLINE - buf->rootY;
    prevhseq = buf->hmarklist->prevhseq;

    drawAnchorCursor0(buf, hseq, prevhseq, tline, eline, 1);
    drawAnchorCursor0(buf, hseq, -1, tline, eline, 0);
    buf->hmarklist->prevhseq = hseq;
}

/* underline an anchor if cursor is on the anchor. */
void
onA(void)
{
    drawAnchorCursor(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* go to the top anchor */
void
topA(void)
{
    HmarkerList *hl = Currentbuf->hmarklist;
    BufferPoint *po;
    Anchor *an;
    int hseq = 0;

    if (Currentbuf->firstLine == NULL)
	return;
    if (!hl || hl->nmark == 0)
	return;

    if (prec_num > hl->nmark)
	hseq = hl->nmark - 1;
    else if (prec_num > 0)
	hseq = prec_num - 1;
    do {
	if (hseq >= hl->nmark)
	    return;
	po = hl->marks + hseq;
	an = retrieveAnchor(Currentbuf->href, po->line, po->pos);
	if (an == NULL)
	    an = retrieveAnchor(Currentbuf->formitem, po->line, po->pos);
	hseq++;
    } while (an == NULL);

    gotoLine(Currentbuf, po->line);
    Currentbuf->pos = po->pos;
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* go to the last anchor */
void
lastA(void)
{
    HmarkerList *hl = Currentbuf->hmarklist;
    BufferPoint *po;
    Anchor *an;
    int hseq;

    if (Currentbuf->firstLine == NULL)
	return;
    if (!hl || hl->nmark == 0)
	return;

    if (prec_num >= hl->nmark)
	hseq = 0;
    else if (prec_num > 0)
	hseq = hl->nmark - prec_num;
    else
	hseq = hl->nmark - 1;
    do {
	if (hseq < 0)
	    return;
	po = hl->marks + hseq;
	an = retrieveAnchor(Currentbuf->href, po->line, po->pos);
	if (an == NULL)
	    an = retrieveAnchor(Currentbuf->formitem, po->line, po->pos);
	hseq--;
    } while (an == NULL);

    gotoLine(Currentbuf, po->line);
    Currentbuf->pos = po->pos;
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* go to the next anchor */
void
nextA(void)
{
    HmarkerList *hl = Currentbuf->hmarklist;
    BufferPoint *po;
    Anchor *an, *pan;
    int i, x, y, n = searchKeyNum();

    if (Currentbuf->firstLine == NULL)
	return;
    if (!hl || hl->nmark == 0)
	return;

    an = retrieveCurrentAnchor(Currentbuf);
    if (an == NULL)
	an = retrieveCurrentForm(Currentbuf);

    y = Currentbuf->currentLine->linenumber;
    x = Currentbuf->pos;

    for (i = 0; i < n; i++) {
	pan = an;
	if (an && an->hseq >= 0) {
	    int hseq = an->hseq + 1;
	    do {
		if (hseq >= hl->nmark) {
		    pan = an;
		    goto _end;
		}
		po = &hl->marks[hseq];
		an = retrieveAnchor(Currentbuf->href, po->line, po->pos);
		if (an == NULL)
		    an = retrieveAnchor(Currentbuf->formitem, po->line,
					po->pos);
		hseq++;
	    } while (an == NULL || an == pan);
	}
	else {
	    an = closest_next_anchor(Currentbuf->href, NULL, x, y);
	    an = closest_next_anchor(Currentbuf->formitem, an, x, y);
	    if (an == NULL) {
		an = pan;
		break;
	    }
	    x = an->start.pos;
	    y = an->start.line;
	}
    }

  _end:
    if (an == NULL || an->hseq < 0)
	return;
    po = &hl->marks[an->hseq];
    gotoLine(Currentbuf, po->line);
    Currentbuf->pos = po->pos;
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* go to the previous anchor */
void
prevA(void)
{
    HmarkerList *hl = Currentbuf->hmarklist;
    BufferPoint *po;
    Anchor *an, *pan;
    int i, x, y, n = searchKeyNum();

    if (Currentbuf->firstLine == NULL)
	return;
    if (!hl || hl->nmark == 0)
	return;

    an = retrieveCurrentAnchor(Currentbuf);
    if (an == NULL)
	an = retrieveCurrentForm(Currentbuf);

    y = Currentbuf->currentLine->linenumber;
    x = Currentbuf->pos;

    for (i = 0; i < n; i++) {
	pan = an;
	if (an && an->hseq >= 0) {
	    int hseq = an->hseq - 1;
	    do {
		if (hseq < 0) {
		    an = pan;
		    goto _end;
		}
		po = hl->marks + hseq;
		an = retrieveAnchor(Currentbuf->href, po->line, po->pos);
		if (an == NULL)
		    an = retrieveAnchor(Currentbuf->formitem, po->line,
					po->pos);
		hseq--;
	    } while (an == NULL || an == pan);
	}
	else {
	    an = closest_prev_anchor(Currentbuf->href, NULL, x, y);
	    an = closest_prev_anchor(Currentbuf->formitem, an, x, y);
	    if (an == NULL) {
		an = pan;
		break;
	    }
	    x = an->start.pos;
	    y = an->start.line;
	}
    }

  _end:
    if (an == NULL || an->hseq < 0)
	return;
    po = hl->marks + an->hseq;
    gotoLine(Currentbuf, po->line);
    Currentbuf->pos = po->pos;
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* go to the next left/right anchor */
static void
nextX(int d, int dy)
{
    HmarkerList *hl = Currentbuf->hmarklist;
    Anchor *an, *pan;
    Line *l;
    int i, x, y, n = searchKeyNum();

    if (Currentbuf->firstLine == NULL)
	return;
    if (!hl || hl->nmark == 0)
	return;

    an = retrieveCurrentAnchor(Currentbuf);
    if (an == NULL)
	an = retrieveCurrentForm(Currentbuf);

    l = Currentbuf->currentLine;
    x = Currentbuf->pos;
    y = l->linenumber;
    pan = NULL;
    for (i = 0; i < n; i++) {
	if (an)
	    x = (d > 0) ? an->end.pos : an->start.pos - 1;
	an = NULL;
	while (1) {
	    for (; x >= 0 && x < l->len; x += d) {
		an = retrieveAnchor(Currentbuf->href, y, x);
		if (!an)
		    an = retrieveAnchor(Currentbuf->formitem, y, x);
		if (an) {
		    pan = an;
		    break;
		}
	    }
	    if (!dy || an)
		break;
	    l = (dy > 0) ? l->next : l->prev;
	    if (!l)
		break;
	    x = (d > 0) ? 0 : l->len - 1;
	    y = l->linenumber;
	}
	if (!an)
	    break;
    }

    if (pan == NULL)
	return;
    gotoLine(Currentbuf, y);
    Currentbuf->pos = pan->start.pos;
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* go to the next downward/upward anchor */
static void
nextY(int d)
{
    HmarkerList *hl = Currentbuf->hmarklist;
    Anchor *an, *pan;
    int i, x, y, n = searchKeyNum();
    int hseq;

    if (Currentbuf->firstLine == NULL)
	return;
    if (!hl || hl->nmark == 0)
	return;

    an = retrieveCurrentAnchor(Currentbuf);
    if (an == NULL)
	an = retrieveCurrentForm(Currentbuf);

    x = Currentbuf->pos;
    y = Currentbuf->currentLine->linenumber + d;
    pan = NULL;
    hseq = -1;
    for (i = 0; i < n; i++) {
	if (an)
	    hseq = abs(an->hseq);
	an = NULL;
	for (; y >= 0 && y <= Currentbuf->lastLine->linenumber; y += d) {
	    an = retrieveAnchor(Currentbuf->href, y, x);
	    if (!an)
		an = retrieveAnchor(Currentbuf->formitem, y, x);
	    if (an && hseq != abs(an->hseq)) {
		pan = an;
		break;
	    }
	}
	if (!an)
	    break;
    }

    if (pan == NULL)
	return;
    gotoLine(Currentbuf, pan->start.line);
    arrangeLine(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* go to the next left anchor */
void
nextL(void)
{
    nextX(-1, 0);
}

/* go to the next left-up anchor */
void
nextLU(void)
{
    nextX(-1, -1);
}

/* go to the next right anchor */
void
nextR(void)
{
    nextX(1, 0);
}

/* go to the next right-down anchor */
void
nextRD(void)
{
    nextX(1, 1);
}

/* go to the next downward anchor */
void
nextD(void)
{
    nextY(1);
}

/* go to the next upward anchor */
void
nextU(void)
{
    nextY(-1);
}

static int
checkBackBuffer(Buffer *buf)
{
    Buffer *fbuf = buf->linkBuffer[LB_N_FRAME];

    if (fbuf) {
	if (fbuf->frameQ)
	    return TRUE;	/* Currentbuf has stacked frames */
	/* when no frames stacked and next is frame source, try next's
	 * nextBuffer */
	if (RenderFrame && fbuf == buf->nextBuffer) {
	    if (fbuf->nextBuffer != NULL)
		return TRUE;
	    else
		return FALSE;
	}
    }

    if (buf->nextBuffer)
	return TRUE;

    return FALSE;
}

/* delete current buffer and back to the previous buffer */
void
backBf(void)
{
    Buffer *buf = Currentbuf->linkBuffer[LB_N_FRAME];

    if (!checkBackBuffer(Currentbuf)) {
	if (close_tab_back && nTab >= 1) {
	    deleteTab(CurrentTab);
	    displayBuffer(Currentbuf, B_FORCE_REDRAW);
	}
	else
	    disp_message("Can't back...", TRUE);
	return;
    }

    delBuffer(Currentbuf);

    if (buf) {
	if (buf->frameQ) {
	    struct frameset *fs;
	    long linenumber = buf->frameQ->linenumber;
	    long top = buf->frameQ->top_linenumber;
	    short pos = buf->frameQ->pos;
	    short currentColumn = buf->frameQ->currentColumn;
	    AnchorList *formitem = buf->frameQ->formitem;

	    fs = popFrameTree(&(buf->frameQ));
	    deleteFrameSet(buf->frameset);
	    buf->frameset = fs;

	    if (buf == Currentbuf) {
		rFrame();
		Currentbuf->topLine = lineSkip(Currentbuf,
					       Currentbuf->firstLine, top - 1,
					       FALSE);
		gotoLine(Currentbuf, linenumber);
		Currentbuf->pos = pos;
		Currentbuf->currentColumn = currentColumn;
		arrangeCursor(Currentbuf);
		formResetBuffer(Currentbuf, formitem);
	    }
	}
	else if (RenderFrame && buf == Currentbuf) {
	    delBuffer(Currentbuf);
	}
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

void
deletePrevBuf()
{
    Buffer *buf = Currentbuf->nextBuffer;
    if (buf)
	delBuffer(buf);
}

static void
cmd_loadURL(char *url, ParsedURL *current, char *referer)
{
    Buffer *buf;

    if (!strncasecmp(url, "mailto:", 7)
#ifdef USE_W3MMAILER
	&& non_null(Mailer) && strchr(url, '?') == NULL
#endif
	) {
	/* invoke external mailer */
	Str to = Strnew_charp(url + 7);
#ifndef USE_W3MMAILER
	char *pos;
	if (!non_null(Mailer)) {
	    disp_err_message("no mailer is specified", TRUE);
	    return;
	}
	if ((pos = strchr(to->ptr, '?')) != NULL)
	    Strtruncate(to, pos - to->ptr);
#endif
	fmTerm();
	system(myExtCommand(Mailer, shell_quote(url_unquote(to->ptr)),
			    FALSE)->ptr);
	fmInit();
	displayBuffer(Currentbuf, B_FORCE_REDRAW);
	pushHashHist(URLHist, url);
	return;
    }
#ifdef USE_NNTP
    if (!strncasecmp(url, "news:", 5) && strchr(url, '@') == NULL) {
	/* news:newsgroup is not supported */
	disp_err_message("news:newsgroup_name is not supported", TRUE);
	return;
    }
#endif				/* USE_NNTP */

    refresh();
    buf = loadGeneralFile(url, current, referer, 0, NULL);
    if (buf == NULL) {
	char *emsg = Sprintf("Can't load %s", conv_from_system(url))->ptr;
	disp_err_message(emsg, FALSE);
    }
    else if (buf != NO_BUFFER) {
	pushBuffer(buf);
	if (RenderFrame && Currentbuf->frameset != NULL)
	    rFrame();
    }
    displayBuffer(Currentbuf, B_NORMAL);
}


/* go to specified URL */
static void
goURL0(char *prompt, int relative)
{
    char *url, *referer;
    ParsedURL p_url, *current;
    Buffer *cur_buf = Currentbuf;

    url = searchKeyData();
    if (url == NULL) {
	Hist *hist = copyHist(URLHist);
	Anchor *a;

	current = baseURL(Currentbuf);
	if (current) {
	    char *c_url = parsedURL2Str(current)->ptr;
	    if (DefaultURLString == DEFAULT_URL_CURRENT)
		url = c_url;
	    else
		pushHist(hist, c_url);
	}
	a = retrieveCurrentAnchor(Currentbuf);
	if (a) {
	    char *a_url;
	    parseURL2(a->url, &p_url, current);
	    a_url = parsedURL2Str(&p_url)->ptr;
	    if (DefaultURLString == DEFAULT_URL_LINK)
		url = a_url;
	    else
		pushHist(hist, a_url);
	}
	url = inputLineHist(prompt, url, IN_URL, hist);
	if (url != NULL)
	    SKIP_BLANKS(url);
    }
#ifdef JP_CHARSET
    if (url != NULL) {
	if (Currentbuf->document_code)
	    url = conv(url, InnerCode, Currentbuf->document_code)->ptr;
	else
	    url = conv_to_system(url);
    }
#endif
    if (url == NULL || *url == '\0') {
	displayBuffer(Currentbuf, B_FORCE_REDRAW);
	return;
    }
    if (*url == '#') {
	gotoLabel(url + 1);
	return;
    }
    if (relative) {
	current = baseURL(Currentbuf);
	referer = parsedURL2Str(&Currentbuf->currentURL)->ptr;
    }
    else {
	current = NULL;
	referer = NULL;
    }
    parseURL2(url, &p_url, current);
    pushHashHist(URLHist, parsedURL2Str(&p_url)->ptr);
    cmd_loadURL(url, current, referer);
    if (Currentbuf != cur_buf)	/* success */
	pushHashHist(URLHist, parsedURL2Str(&Currentbuf->currentURL)->ptr);
}

void
goURL(void)
{
    goURL0("Goto URL: ", FALSE);
}

void
gorURL(void)
{
    goURL0("Goto relative URL: ", TRUE);
}

static void
cmd_loadBuffer(Buffer *buf, int prop, int linkid)
{
    if (buf == NULL) {
	disp_err_message("Can't load string", FALSE);
    }
    else if (buf != NO_BUFFER) {
	buf->bufferprop |= (BP_INTERNAL | prop);
	if (!(buf->bufferprop & BP_NO_URL))
	    copyParsedURL(&buf->currentURL, &Currentbuf->currentURL);
	if (linkid != LB_NOLINK) {
	    buf->linkBuffer[REV_LB[linkid]] = Currentbuf;
	    Currentbuf->linkBuffer[linkid] = buf;
	}
	pushBuffer(buf);
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

/* load bookmark */
void
ldBmark(void)
{
    cmd_loadURL(BookmarkFile, NULL, NO_REFERER);
}


/* Add current to bookmark */
void
adBmark(void)
{
    Str tmp;

    tmp = Sprintf("file://%s/" W3MBOOKMARK_CMDNAME
		  "?mode=panel&bmark=%s&url=%s&title=%s",
		  w3m_lib_dir(),
		  (Str_form_quote(Strnew_charp(BookmarkFile)))->ptr,
		  (Str_form_quote(parsedURL2Str(&Currentbuf->currentURL)))->
		  ptr,
		  (Str_form_quote(Strnew_charp(Currentbuf->buffername)))->ptr);
    cmd_loadURL(tmp->ptr, NULL, NO_REFERER);
}

/* option setting */
void
ldOpt(void)
{
    cmd_loadBuffer(load_option_panel(), BP_NO_URL, LB_NOLINK);
}

/* set an option */
void
setOpt(void)
{
    char *opt;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    opt = searchKeyData();
    if (opt == NULL || *opt == '\0' || strchr(opt, '=') == NULL) {
	if (opt != NULL && *opt != '\0') {
	    char *v = get_param_option(opt);
	    opt = Sprintf("%s=%s", opt, v ? v : "")->ptr;
	}
	opt = inputStrHist("Set option: ", opt, TextHist);
	if (opt == NULL || *opt == '\0') {
	    displayBuffer(Currentbuf, B_NORMAL);
	    return;
	}
    }
    if (set_param_option(opt))
	sync_with_option();
#ifdef USE_IMAGE
    if (activeImage)
	displayBuffer(Currentbuf, B_REDRAW_IMAGE);
#endif
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

/* error message list */
void
msgs(void)
{
    cmd_loadBuffer(message_list_panel(), BP_NO_URL, LB_NOLINK);
}

/* page info */
void
pginfo(void)
{
    Buffer *buf;

    if ((buf = Currentbuf->linkBuffer[LB_N_INFO]) != NULL) {
	Currentbuf = buf;
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    if ((buf = Currentbuf->linkBuffer[LB_INFO]) != NULL)
	delBuffer(buf);
    buf = page_info_panel(Currentbuf);
#ifdef JP_CHARSET
    if (buf != NULL)
	buf->document_code = Currentbuf->document_code;
#endif				/* JP_CHARSET */
    cmd_loadBuffer(buf, BP_NORMAL, LB_INFO);
}

void
follow_map(struct parsed_tagarg *arg)
{
#ifdef MENU_MAP
    Anchor *an;
    MapArea *a;
    int x, y;
    ParsedURL p_url;

    an = retrieveCurrentImg(Currentbuf);
    x = Currentbuf->cursorX + Currentbuf->rootX;
    y = Currentbuf->cursorY + Currentbuf->rootY;
    a = follow_map_menu(Currentbuf, arg, an, x, y);
    if (a == NULL || a->url == NULL || *(a->url) == '\0')
	return;
    if (*(a->url) == '#') {
	gotoLabel(a->url + 1);
	return;
    }
    parseURL2(a->url, &p_url, baseURL(Currentbuf));
    pushHashHist(URLHist, parsedURL2Str(&p_url)->ptr);
    if (check_target && open_tab_blank && a->target &&
	(!strcasecmp(a->target, "_new") || !strcasecmp(a->target, "_blank"))) {
	Buffer *buf;

	_newT();
	buf = Currentbuf;
	cmd_loadURL(a->url, baseURL(Currentbuf),
		parsedURL2Str(&Currentbuf->currentURL)->ptr);
	if (buf != Currentbuf)
	    delBuffer(buf);
	else
	    deleteTab(CurrentTab);
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    cmd_loadURL(a->url, baseURL(Currentbuf),
		parsedURL2Str(&Currentbuf->currentURL)->ptr);
#else
    Buffer *buf;

    buf = follow_map_panel(Currentbuf, arg);
    if (buf != NULL)
	cmd_loadBuffer(buf, BP_NORMAL, LB_NOLINK);
#endif
}

#ifdef USE_COOKIE
/* cookie list */
void
cooLst(void)
{
    Buffer *buf;

    buf = cookie_list_panel();
    if (buf != NULL)
	cmd_loadBuffer(buf, BP_NO_URL, LB_NOLINK);
}
#endif				/* USE_COOKIE */

#ifdef USE_HISTORY
/* History page */
void
ldHist(void)
{
    cmd_loadBuffer(historyBuffer(URLHist), BP_NO_URL, LB_NOLINK);
}
#endif				/* USE_HISTORY */

/* download HREF link */
void
svA(void)
{
    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    do_download = TRUE;
    followA();
    do_download = FALSE;
}

/* download IMG link */
void
svI(void)
{
    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    do_download = TRUE;
    followI();
    do_download = FALSE;
}

/* save buffer */
void
svBuf(void)
{
    char *qfile = NULL, *file;
    FILE *f;
    int is_pipe;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    file = searchKeyData();
    if (file == NULL || *file == '\0') {
	qfile = inputLineHist("Save buffer to: ", NULL, IN_COMMAND, SaveHist);
	if (qfile == NULL || *qfile == '\0') {
	    displayBuffer(Currentbuf, B_FORCE_REDRAW);
	    return;
	}
    }
    file = conv_to_system(qfile ? qfile : file);
    if (*file == '|') {
	is_pipe = TRUE;
	f = popen(file + 1, "w");
    }
    else {
	if (qfile) {
	    file = unescape_spaces(Strnew_charp(qfile))->ptr;
	    file = conv_to_system(file);
	}
	file = expandName(file);
	if (checkOverWrite(file) < 0)
	    return;
	f = fopen(file, "w");
	is_pipe = FALSE;
    }
    if (f == NULL) {
	char *emsg = Sprintf("Can't open %s", conv_from_system(file))->ptr;
	disp_err_message(emsg, TRUE);
	return;
    }
    saveBuffer(Currentbuf, f);
    if (is_pipe)
	pclose(f);
    else
	fclose(f);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* save source */
void
svSrc(void)
{
    char *file;

    if (Currentbuf->sourcefile == NULL)
	return;
    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    PermitSaveToPipe = TRUE;
    if (Currentbuf->real_scheme == SCM_LOCAL)
	file = conv_from_system(guess_save_name(NULL,
						Currentbuf->currentURL.
						real_file));
    else
	file = guess_save_name(Currentbuf, Currentbuf->currentURL.file);
    doFileCopy(Currentbuf->sourcefile, file);
    PermitSaveToPipe = FALSE;
    displayBuffer(Currentbuf, B_NORMAL);
}

static void
_peekURL(int only_img)
{

    Anchor *a;
    ParsedURL pu;
    static Str s = NULL;
    static int offset = 0, n;

    if (Currentbuf->firstLine == NULL)
	return;
    if (CurrentKey == prev_key && s != NULL) {
	if (s->length - offset >= COLS)
	    offset++;
	else if (s->length <= offset)	/* bug ? */
	    offset = 0;
	goto disp;
    }
    else {
	offset = 0;
    }
    a = (only_img ? NULL : retrieveCurrentAnchor(Currentbuf));
    if (a == NULL) {
	a = (only_img ? NULL : retrieveCurrentForm(Currentbuf));
	if (a == NULL) {
	    a = retrieveCurrentImg(Currentbuf);
	    if (a == NULL) {
		s = NULL;
		return;
	    }
	}
	else {
	    s = Strnew_charp(form2str((FormItemList *)a->url));
	    goto disp;
	}
    }
    parseURL2(a->url, &pu, baseURL(Currentbuf));
    s = parsedURL2Str(&pu);
  disp:
    n = searchKeyNum();
    if (n > 1 && s->length > (n - 1) * (COLS - 1))
	disp_message_nomouse(&s->ptr[(n - 1) * (COLS - 1)], TRUE);
    else
	disp_message_nomouse(&s->ptr[offset], TRUE);
}

/* peek URL */
void
peekURL(void)
{
    _peekURL(0);
}

/* peek URL of image */
void
peekIMG(void)
{
    _peekURL(1);
}

/* show current URL */
static Str
currentURL(void)
{
    if (Currentbuf->bufferprop & BP_INTERNAL)
	return Strnew_size(0);
    return parsedURL2Str(&Currentbuf->currentURL);
}

void
curURL(void)
{
    static Str s = NULL;
    static int offset = 0, n;

    if (Currentbuf->bufferprop & BP_INTERNAL)
	return;
    if (CurrentKey == prev_key && s != NULL) {
	if (s->length - offset >= COLS)
	    offset++;
	else if (s->length <= offset)	/* bug ? */
	    offset = 0;
    }
    else {
	offset = 0;
	s = currentURL();
    }
    n = searchKeyNum();
    if (n > 1 && s->length > (n - 1) * (COLS - 1))
	disp_message_nomouse(&s->ptr[(n - 1) * (COLS - 1)], TRUE);
    else
	disp_message_nomouse(&s->ptr[offset], TRUE);
}

/* view HTML source */
void
vwSrc(void)
{
    char *fn;
    Buffer *buf;

    if (Currentbuf->type == NULL || Currentbuf->bufferprop & BP_FRAME)
	return;
#ifdef USE_IMAGE
    if (!strncasecmp(Currentbuf->real_type, "image/", 6))
	return;
#endif
    if ((buf = Currentbuf->linkBuffer[LB_SOURCE]) != NULL ||
	(buf = Currentbuf->linkBuffer[LB_N_SOURCE]) != NULL) {
	Currentbuf = buf;
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    if (Currentbuf->sourcefile == NULL) {
	if (Currentbuf->pagerSource &&
	    !strcasecmp(Currentbuf->type, "text/plain")) {
	    FILE *f;
	    Str tmpf = tmpfname(TMPF_SRC, NULL);
	    pushText(fileToDelete, tmpf->ptr);
	    f = fopen(tmpf->ptr, "w");
	    if (f == NULL)
		return;
	    saveBuffer(Currentbuf, f);
	    fclose(f);
	    fn = tmpf->ptr;
	}
	else {
	    return;
	}
    }
    else if (Currentbuf->real_scheme == SCM_LOCAL) {
	fn = Currentbuf->filename;
    }
    else {
	fn = Currentbuf->sourcefile;
    }
    if (!strcasecmp(Currentbuf->type, "text/html")) {
#ifdef JP_CHARSET
	char old_code = DocumentCode;
	DocumentCode = Currentbuf->document_code;
#endif
	buf = loadFile(fn);
#ifdef JP_CHARSET
	DocumentCode = old_code;
#endif
	if (buf == NULL)
	    return;
	buf->type = "text/plain";
	if (Currentbuf->real_type &&
	    !strcasecmp(Currentbuf->real_type, "text/html"))
	    buf->real_type = "text/plain";
	else
	    buf->real_type = Currentbuf->real_type;
	buf->bufferprop |= BP_SOURCE;
	buf->buffername = Sprintf("source of %s", Currentbuf->buffername)->ptr;
	buf->linkBuffer[LB_N_SOURCE] = Currentbuf;
	Currentbuf->linkBuffer[LB_SOURCE] = buf;
    }
    else if (!strcasecmp(Currentbuf->type, "text/plain")) {
	DefaultType = "text/html";
	buf = loadGeneralFile(file_to_url(fn), NULL, NO_REFERER, 0, NULL);
	DefaultType = NULL;
	if (buf == NULL || buf == NO_BUFFER)
	    return;
	if (Currentbuf->real_type &&
	    !strcasecmp(Currentbuf->real_type, "text/plain"))
	    buf->real_type = "text/html";
	else
	    buf->real_type = Currentbuf->real_type;
	if (!strcmp(buf->buffername, conv_from_system(lastFileName(fn))))
	    buf->buffername =
		Sprintf("HTML view of %s", Currentbuf->buffername)->ptr;
	buf->linkBuffer[LB_SOURCE] = Currentbuf;
	Currentbuf->linkBuffer[LB_N_SOURCE] = buf;
    }
    else {
	return;
    }
    buf->currentURL = Currentbuf->currentURL;
    buf->real_scheme = Currentbuf->real_scheme;
    buf->sourcefile = Currentbuf->sourcefile;
    buf->clone = Currentbuf->clone;
    (*buf->clone)++;
    pushBuffer(buf);
    displayBuffer(Currentbuf, B_NORMAL);
}

/* reload */
void
reload(void)
{
    Buffer *buf, *fbuf = NULL, sbuf;
#ifdef JP_CHARSET
    char old_code;
#endif
    Str url;
    FormList *request;
    int multipart;

    if (Currentbuf->bufferprop & BP_INTERNAL) {
	disp_err_message("Can't reload...", FALSE);
	return;
    }
    if (Currentbuf->currentURL.scheme == SCM_LOCAL &&
	!strcmp(Currentbuf->currentURL.file, "-")) {
	/* file is std input */
	disp_err_message("Can't reload stdin", TRUE);
	return;
    }
    copyBuffer(&sbuf, Currentbuf);
    if (Currentbuf->bufferprop & BP_FRAME &&
	(fbuf = Currentbuf->linkBuffer[LB_N_FRAME])) {
	if (fmInitialized) {
	    message("Rendering frame", 0, 0);
	    refresh();
	}
	if (!(buf = renderFrame(fbuf, 1)))
	    return;
	if (fbuf->linkBuffer[LB_FRAME]) {
	    if (buf->sourcefile &&
		fbuf->linkBuffer[LB_FRAME]->sourcefile &&
		!strcmp(buf->sourcefile,
			fbuf->linkBuffer[LB_FRAME]->sourcefile))
		fbuf->linkBuffer[LB_FRAME]->sourcefile = NULL;
	    delBuffer(fbuf->linkBuffer[LB_FRAME]);
	}
	fbuf->linkBuffer[LB_FRAME] = buf;
	buf->linkBuffer[LB_N_FRAME] = fbuf;
	pushBuffer(buf);
	Currentbuf = buf;
	if (Currentbuf->firstLine)
	    restorePosition(Currentbuf, &sbuf);
	displayBuffer(Currentbuf, B_FORCE_REDRAW);
	return;
    }
    else if (Currentbuf->frameset != NULL)
	fbuf = Currentbuf->linkBuffer[LB_FRAME];
    multipart = 0;
    if (Currentbuf->form_submit) {
	request = Currentbuf->form_submit->parent;
	if (request->method == FORM_METHOD_POST
	    && request->enctype == FORM_ENCTYPE_MULTIPART) {
	    Str query;
	    struct stat st;
	    multipart = 1;
	    query_from_followform(&query, Currentbuf->form_submit, multipart);
	    stat(request->body, &st);
	    request->length = st.st_size;
	}
    }
    else {
	request = NULL;
    }
    url = parsedURL2Str(&Currentbuf->currentURL);
    message("Reloading...", 0, 0);
    refresh();

#ifdef JP_CHARSET
    old_code = DocumentCode;
    DocumentCode = Currentbuf->document_code;
#endif
    SearchHeader = Currentbuf->search_header;
    DefaultType = Currentbuf->real_type;
    buf = loadGeneralFile(url->ptr, NULL, NO_REFERER, RG_NOCACHE, request);
#ifdef JP_CHARSET
    DocumentCode = old_code;
#endif
    SearchHeader = FALSE;
    DefaultType = NULL;

    if (multipart)
	unlink(request->body);
    if (buf == NULL) {
	disp_err_message("Can't reload...", FALSE);
	return;
    }
    else if (buf == NO_BUFFER) {
	return;
    }
    if (fbuf != NULL)
	Firstbuf = deleteBuffer(Firstbuf, fbuf);
    repBuffer(Currentbuf, buf);
    if ((buf->type != NULL) && (sbuf.type != NULL) &&
	((!strcasecmp(buf->type, "text/plain") &&
	  !strcasecmp(sbuf.type, "text/html")) ||
	 (!strcasecmp(buf->type, "text/html") &&
	  !strcasecmp(sbuf.type, "text/plain")))) {
	vwSrc();
	if (Currentbuf != buf)
	    Firstbuf = deleteBuffer(Firstbuf, buf);
    }
    Currentbuf->search_header = sbuf.search_header;
    Currentbuf->form_submit = sbuf.form_submit;
    if (Currentbuf->firstLine)
	restorePosition(Currentbuf, &sbuf);
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

/* mark URL-like patterns as anchors */
void
chkURLBuffer(Buffer *buf)
{
    static char *url_like_pat[] = {
	"https?://[a-zA-Z0-9][a-zA-Z0-9:%\\-\\./?=~_\\&+@#,\\$;]*[a-zA-Z0-9_/=]",
	"file:/[a-zA-Z0-9:%\\-\\./=_\\+@#,\\$;]*",
#ifdef USE_GOPHER
	"gopher://[a-zA-Z0-9][a-zA-Z0-9:%\\-\\./_]*",
#endif				/* USE_GOPHER */
	"ftp://[a-zA-Z0-9][a-zA-Z0-9:%\\-\\./=_+@#,\\$]*[a-zA-Z0-9_/]",
#ifdef USE_NNTP
	"news:[^<> 	][^<> 	]*",
	"nntp://[a-zA-Z0-9][a-zA-Z0-9:%\\-\\./_]*",
#endif				/* USE_NNTP */
#ifndef USE_W3MMAILER		/* see also chkExternalURIBuffer() */
	"mailto:[^<> 	][^<> 	]*@[a-zA-Z0-9][a-zA-Z0-9\\-\\._]*[a-zA-Z0-9]",
#endif
#ifdef INET6
	"https?://[a-zA-Z0-9:%\\-\\./_@]*\\[[a-fA-F0-9:][a-fA-F0-9:\\.]*\\][a-zA-Z0-9:%\\-\\./?=~_\\&+@#,\\$;]*",
	"ftp://[a-zA-Z0-9:%\\-\\./_@]*\\[[a-fA-F0-9:][a-fA-F0-9:\\.]*\\][a-zA-Z0-9:%\\-\\./=_+@#,\\$]*",
#endif				/* INET6 */
	NULL
    };
    int i;
    for (i = 0; url_like_pat[i]; i++) {
	reAnchor(buf, url_like_pat[i]);
    }
#ifdef USE_EXTERNAL_URI_LOADER
    chkExternalURIBuffer(buf);
#endif
    buf->check_url |= CHK_URL;
}

void
chkURL(void)
{
    chkURLBuffer(Currentbuf);
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

void
chkWORD(void)
{
    char *p;
    int spos, epos;
    p = getCurWord(Currentbuf, &spos, &epos, ":\"\'`<>");
    if (p == NULL)
	return;
    reAnchorWord(Currentbuf, Currentbuf->currentLine, spos, epos);
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

#ifdef USE_NNTP
/* mark Message-ID-like patterns as NEWS anchors */
void
chkNMIDBuffer(Buffer *buf)
{
    static char *url_like_pat[] = {
	"<[^<> 	][^<> 	]*@[A-z0-9\\.\\-_]+>",
	NULL,
    };
    int i;
    for (i = 0; url_like_pat[i]; i++) {
	reAnchorNews(buf, url_like_pat[i]);
    }
    buf->check_url |= CHK_NMID;
}

void
chkNMID(void)
{
    chkNMIDBuffer(Currentbuf);
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}
#endif				/* USE_NNTP */

/* render frame */
void
rFrame(void)
{
    Buffer *buf;

    if ((buf = Currentbuf->linkBuffer[LB_FRAME]) != NULL) {
	Currentbuf = buf;
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    if (Currentbuf->frameset == NULL) {
	if ((buf = Currentbuf->linkBuffer[LB_N_FRAME]) != NULL) {
	    Currentbuf = buf;
	    displayBuffer(Currentbuf, B_NORMAL);
	}
	return;
    }
    if (fmInitialized) {
	message("Rendering frame", 0, 0);
	refresh();
    }
    buf = renderFrame(Currentbuf, 0);
    if (buf == NULL)
	return;
    buf->linkBuffer[LB_N_FRAME] = Currentbuf;
    Currentbuf->linkBuffer[LB_FRAME] = buf;
    pushBuffer(buf);
    if (fmInitialized && display_ok)
	displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

/* spawn external browser */
static void
invoke_browser(char *url)
{
    Str cmd;
    char *browser = NULL;
    int bg = 0, len;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    browser = searchKeyData();
    if (browser == NULL || *browser == '\0') {
	switch (prec_num) {
	case 0:
	case 1:
	    browser = ExtBrowser;
	    break;
	case 2:
	    browser = ExtBrowser2;
	    break;
	case 3:
	    browser = ExtBrowser3;
	    break;
	}
	if (browser == NULL || *browser == '\0') {
	    browser = inputStr("Browse command: ", NULL);
	    if (browser != NULL)
		browser = conv_to_system(browser);
	}
    }
    else {
	browser = conv_to_system(browser);
    }
    if (browser == NULL || *browser == '\0')
	return;

    if ((len = strlen(browser)) >= 2 && browser[len - 1] == '&' &&
	browser[len - 2] != '\\') {
	browser = allocStr(browser, len - 2);
	bg = 1;
    }
    cmd = myExtCommand(browser, shell_quote(url), FALSE);
    Strremovetrailingspaces(cmd);
    fmTerm();
    mySystem(cmd->ptr, bg);
    fmInit();
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

void
extbrz()
{
    if (Currentbuf->bufferprop & BP_INTERNAL) {
	disp_err_message("Can't browse...", FALSE);
	return;
    }
    if (Currentbuf->currentURL.scheme == SCM_LOCAL &&
	!strcmp(Currentbuf->currentURL.file, "-")) {
	/* file is std input */
	disp_err_message("Can't browse stdin", TRUE);
	return;
    }
    invoke_browser(parsedURL2Str(&Currentbuf->currentURL)->ptr);
}

void
linkbrz()
{
    Anchor *a;
    ParsedURL pu;

    if (Currentbuf->firstLine == NULL)
	return;
    a = retrieveCurrentAnchor(Currentbuf);
    if (a == NULL)
	return;
    parseURL2(a->url, &pu, baseURL(Currentbuf));
    invoke_browser(parsedURL2Str(&pu)->ptr);
}

/* show current line number and number of lines in the entire document */
void
curlno()
{
    Str tmp;
    int cur = 0, all, col, len = 0;

    if (Currentbuf->currentLine != NULL) {
	Line *l = Currentbuf->currentLine;
	cur = l->real_linenumber;
	if (l->width < 0)
	    l->width = COLPOS(l, l->len);
	len = l->width;
    }
    col = Currentbuf->currentColumn + Currentbuf->cursorX + 1;
    all =
	(Currentbuf->lastLine ? Currentbuf->lastLine->
	 real_linenumber : Currentbuf->allLine);
    if (all == 0 && Currentbuf->lastLine != NULL)
	all = Currentbuf->currentLine->real_linenumber;
    if (all == 0)
	all = 1;
    if (Currentbuf->pagerSource && !(Currentbuf->bufferprop & BP_CLOSE))
	tmp = Sprintf("line %d col %d/%d", cur, col, len);
    else
	tmp = Sprintf("line %d/%d (%d%%) col %d/%d",
		      cur, all, cur * 100 / all, col, len);
#ifdef JP_CHARSET
    Strcat_charp(tmp, "  ");
    Strcat_charp(tmp, code_to_str(Currentbuf->document_code));
#endif				/* not JP_CHARSET */

    disp_message(tmp->ptr, FALSE);
}

#ifdef USE_IMAGE
void
dispI(void)
{
    if (!displayImage)
	initImage();
    if (!activeImage)
	return;
    displayImage = TRUE;
    /*
     * if (!(Currentbuf->type && !strcmp(Currentbuf->type, "text/html")))
     * return;
     */
    Currentbuf->image_flag = IMG_FLAG_AUTO;
    Currentbuf->need_reshape = TRUE;
    displayBuffer(Currentbuf, B_REDRAW_IMAGE);
}

void
stopI(void)
{
    if (!activeImage)
	return;
    /*
     * if (!(Currentbuf->type && !strcmp(Currentbuf->type, "text/html")))
     * return;
     */
    Currentbuf->image_flag = IMG_FLAG_SKIP;
    displayBuffer(Currentbuf, B_REDRAW_IMAGE);
}
#endif

#ifdef USE_MOUSE

static TabBuffer *
posTab(int x, int y)
{
    TabBuffer *t;
    int i, n, col = COLS - 2;

    if (col <= 0)
	return NULL;
    n = x * N_TAB / col + y * N_TAB;
    for (t = FirstTab, i = 0; t && i < n; t = t->nextTab, i++)
	;
    return t;
}

static void
process_mouse(int btn, int x, int y)
{
    int delta_x, delta_y, i;
    static int press_btn = MOUSE_BTN_RESET, press_x, press_y;
    TabBuffer *t;
    int ny = 0;

    if (nTab > 1)
	ny = (nTab - 1) / N_TAB + 1;
    if (btn == MOUSE_BTN_UP) {
	switch (press_btn) {
	case MOUSE_BTN1_DOWN:
	    if (nTab > 1 && y < ny) {
		if (press_y == y && press_x == x) {
		    if (y == 0 && x >= COLS - 2) {
			deleteTab(CurrentTab);
			displayBuffer(Currentbuf, B_NORMAL);
		    }
		    t = posTab(x, y);
		    if (t)
			CurrentTab = t;
		    displayBuffer(Currentbuf, B_FORCE_REDRAW);
		    return;
		}
		else if (press_y < ny) {
		    moveTab(posTab(press_x, press_y), posTab(x, y),
		    	    (press_y == y) ? (press_x < x) : (press_y < y));
		    return;
		}
		else if (press_x >= Currentbuf->rootX) {
		    Buffer *buf = Currentbuf;
		    int cx = Currentbuf->cursorX, cy = Currentbuf->cursorY;

		    t = posTab(x, y);
		    if (t == NULL)
			return;
		    cursorXY(Currentbuf, press_x - Currentbuf->rootX,
			     press_y - Currentbuf->rootY);
		    if (Currentbuf->cursorY == press_y - Currentbuf->rootY &&
			(Currentbuf->cursorX == press_x - Currentbuf->rootX
#ifdef JP_CHARSET
			 || (Currentbuf->currentLine != NULL &&
			     (Currentbuf->currentLine->propBuf[Currentbuf->pos]
			      & PC_KANJI1) && Currentbuf->cursorX == press_x
			     - Currentbuf->rootX - 1)
#endif
			)) {
			onA();
			followTab(t);
		    }
		    if (buf == Currentbuf)
			cursorXY(Currentbuf, cx, cy);
		}
		return;
	    }
	    if (press_x != x || press_y != y) {
		delta_x = x - press_x;
		delta_y = y - press_y;

		if (abs(delta_x) < abs(delta_y) / 3)
		    delta_x = 0;
		if (abs(delta_y) < abs(delta_x) / 3)
		    delta_y = 0;
		if (reverse_mouse) {
		    delta_y = -delta_y;
		    delta_x = -delta_x;
		}
		if (delta_y > 0) {
		    prec_num = delta_y;
		    ldown1();
		}
		else if (delta_y < 0) {
		    prec_num = -delta_y;
		    lup1();
		}
		if (delta_x > 0) {
		    prec_num = delta_x;
		    col1L();
		}
		else if (delta_x < 0) {
		    prec_num = -delta_x;
		    col1R();
		}
	    }
	    else {
		if (y == LASTLINE) {
		    switch (x) {
		    case 0:
		    case 1:
			backBf();
			break;
		    case 2:
		    case 3:
			pgBack();
			break;
		    case 4:
		    case 5:
			pgFore();
			break;
		    }
		    return;
		}
		if (y == Currentbuf->cursorY + Currentbuf->rootY &&
		    (x == Currentbuf->cursorX + Currentbuf->rootX
#ifdef JP_CHARSET
		     || (Currentbuf->currentLine != NULL &&
			 (Currentbuf->currentLine->
			  propBuf[Currentbuf->pos] & PC_KANJI1)
			 && x == Currentbuf->cursorX + Currentbuf->rootX + 1)
#endif				/* JP_CHARSET */
		    )) {
		    followA();
		    return;
		}
		if (x >= Currentbuf->rootX)
		    cursorXY(Currentbuf, x - Currentbuf->rootX,
			     y - Currentbuf->rootY);
		displayBuffer(Currentbuf, B_NORMAL);

	    }
	    break;
	case MOUSE_BTN2_DOWN:
	    if (nTab > 1 && y < ny) {
		if (press_y == y && press_x == x) {
		    t = posTab(x, y);
		    if (t) {
			deleteTab(t);
			displayBuffer(Currentbuf, B_FORCE_REDRAW);
		    }
		}
		return;
	    }
	    backBf();
	    break;
	case MOUSE_BTN3_DOWN:
#ifdef USE_MENU
	    if (x >= Currentbuf->rootX && y > ny)
		cursorXY(Currentbuf, x - Currentbuf->rootX,
			 y - Currentbuf->rootY);
	    onA();
	    mainMenu(x, y);
#endif				/* USE_MENU */
	    break;
	case MOUSE_BTN4_DOWN_RXVT:
	    for (i = 0; i < MOUSE_SCROLL_LINE; i++)
		ldown1();
	    break;
	case MOUSE_BTN5_DOWN_RXVT:
	    for (i = 0; i < MOUSE_SCROLL_LINE; i++)
		lup1();
	    break;
	}
    }
    else if (btn == MOUSE_BTN4_DOWN_XTERM) {
	for (i = 0; i < MOUSE_SCROLL_LINE; i++)
	    ldown1();
    }
    else if (btn == MOUSE_BTN5_DOWN_XTERM) {
	for (i = 0; i < MOUSE_SCROLL_LINE; i++)
	    lup1();
    }

    if (btn != MOUSE_BTN4_DOWN_RXVT || press_btn == MOUSE_BTN_RESET) {
	press_btn = btn;
	press_x = x;
	press_y = y;
    }
    else {
	press_btn = MOUSE_BTN_RESET;
    }
}

void
msToggle(void)
{
    if (use_mouse) {
	use_mouse = FALSE;
    }
    else {
	use_mouse = TRUE;
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

void
mouse()
{
    int btn, x, y;

    btn = (unsigned char)getch() - 32;
    x = (unsigned char)getch() - 33;
    if (x < 0)
	x += 0x100;
    y = (unsigned char)getch() - 33;
    if (y < 0)
	y += 0x100;

    if (x < 0 || x >= COLS || y < 0 || y > LASTLINE)
	return;
    process_mouse(btn, x, y);
}

#ifdef USE_GPM
int
gpm_process_mouse(Gpm_Event * event, void *data)
{
    int btn = MOUSE_BTN_RESET, x, y;
    if (event->type & GPM_UP)
	btn = MOUSE_BTN_UP;
    else if (event->type & GPM_DOWN) {
	switch (event->buttons) {
	case GPM_B_LEFT:
	    btn = MOUSE_BTN1_DOWN;
	    break;
	case GPM_B_MIDDLE:
	    btn = MOUSE_BTN2_DOWN;
	    break;
	case GPM_B_RIGHT:
	    btn = MOUSE_BTN3_DOWN;
	    break;
	}
    }
    else {
	GPM_DRAWPOINTER(event);
	return 0;
    }
    x = event->x;
    y = event->y;
    process_mouse(btn, x - 1, y - 1);
    return 0;
}
#endif				/* USE_GPM */

#ifdef USE_SYSMOUSE
int
sysm_process_mouse(int x, int y, int nbs, int obs)
{
    int btn;
    int bits;

    if (obs & ~nbs)
	btn = MOUSE_BTN_UP;
    else if (nbs & ~obs) {
	bits = nbs & ~obs;
	btn = bits & 0x1 ? MOUSE_BTN1_DOWN :
	    (bits & 0x2 ? MOUSE_BTN2_DOWN :
	     (bits & 0x4 ? MOUSE_BTN3_DOWN : 0));
    }
    else			/* nbs == obs */
	return 0;
    process_mouse(btn, x, y);
    return 0;
}
#endif				/* USE_SYSMOUSE */
#endif				/* USE_MOUSE */

void
dispVer()
{
    disp_message(Sprintf("w3m version %s", w3m_version)->ptr, FALSE);
}

void
wrapToggle(void)
{
    if (WrapSearch) {
	WrapSearch = FALSE;
	disp_message("Wrap search off", FALSE);
    }
    else {
	WrapSearch = TRUE;
	disp_message("Wrap search on", FALSE);
    }
}

static int
is_wordchar(int c, const char *badchars)
{
    if (badchars)
	return !(IS_SPACE(c) || strchr(badchars, c));
    else
	return IS_ALPHA(c);
}

static char *
getCurWord(Buffer *buf, int *spos, int *epos, const char *badchars)
{
    char *p;
    Line *l = buf->currentLine;
    int b, e;

    *spos = 0;
    *epos = 0;
    if (l == NULL)
	return NULL;
    p = l->lineBuf;
    e = buf->pos;
    while (e > 0 && !is_wordchar(p[e], badchars))
	e--;
    if (!is_wordchar(p[e], badchars))
	return NULL;
    b = e;
    while (b > 0 && is_wordchar(p[b - 1], badchars))
	b--;
    while (e < l->len && is_wordchar(p[e], badchars))
	e++;
    *spos = b;
    *epos = e;
    return &p[b];
}

static char *
GetWord(Buffer *buf)
{
    int b, e;
    char *p;

    if ((p = getCurWord(buf, &b, &e, 0)) != NULL) {
	return Strnew_charp_n(p, e - b)->ptr;
    }
    return NULL;
}

#ifdef USE_DICT
static void
execdict(char *word)
{
    char *w, *dictcmd;
    Buffer *buf;

    if (!UseDictCommand || word == NULL || *word == '\0') {
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    w = conv_to_system(word);
    if (*w == '\0') {
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    dictcmd = Sprintf("%s?%s", DictCommand,
		      Str_form_quote(Strnew_charp(w))->ptr)->ptr;
    buf = loadGeneralFile(dictcmd, NULL, NO_REFERER, 0, NULL);
    if (buf == NULL) {
	disp_message("Execution failed", FALSE);
    }
    else {
	buf->filename = w;
	buf->buffername = Sprintf("%s %s", DICTBUFFERNAME, word)->ptr;
	if (buf->type == NULL)
	    buf->type = "text/plain";
	pushBuffer(buf);
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

void
dictword(void)
{
    execdict(inputStr("(dictionary)!", ""));
}

void
dictwordat(void)
{
    execdict(GetWord(Currentbuf));
}
#endif				/* USE_DICT */

void
set_buffer_environ(Buffer *buf)
{
    Anchor *a;
    Str s;
    ParsedURL pu;

    if (buf == NULL)
	return;
    set_environ("W3M_SOURCEFILE", buf->sourcefile);
    set_environ("W3M_FILENAME", buf->filename);
    set_environ("W3M_CURRENT_WORD", GetWord(buf));
    set_environ("W3M_TITLE", buf->buffername);
    set_environ("W3M_URL", parsedURL2Str(&buf->currentURL)->ptr);
    if (buf->real_type)
	set_environ("W3M_TYPE", buf->real_type);
    else
	set_environ("W3M_TYPE", "unknown");
#ifdef JP_CHARSET
    set_environ("W3M_CHARSET", code_to_str(buf->document_code));
#endif				/* JP_CHARSET */
    a = retrieveCurrentAnchor(buf);
    if (a == NULL) {
	set_environ("W3M_CURRENT_LINK", "");
    }
    else {
	parseURL2(a->url, &pu, baseURL(buf));
	s = parsedURL2Str(&pu);
	set_environ("W3M_CURRENT_LINK", s->ptr);
    }
    a = retrieveCurrentImg(buf);
    if (a == NULL) {
	set_environ("W3M_CURRENT_IMG", "");
    }
    else {
	parseURL2(a->url, &pu, baseURL(buf));
	s = parsedURL2Str(&pu);
	set_environ("W3M_CURRENT_IMG", s->ptr);
    }
    a = retrieveCurrentForm(buf);
    if (a == NULL) {
	set_environ("W3M_CURRENT_FORM", "");
    }
    else {
	s = Strnew_charp(form2str((FormItemList *)a->url));
	set_environ("W3M_CURRENT_FORM", s->ptr);
    }
}

char *
searchKeyData(void)
{
    char *data = NULL;

    if (CurrentKeyData != NULL && *CurrentKeyData != '\0')
	data = CurrentKeyData;
    else if (CurrentCmdData != NULL && *CurrentCmdData != '\0')
	data = CurrentCmdData;
    else if (CurrentKey >= 0)
	data = getKeyData(CurrentKey);
    CurrentKeyData = NULL;
    CurrentCmdData = NULL;
    if (data == NULL || *data == '\0')
	return NULL;
    return allocStr(data, -1);
}

static int
searchKeyNum(void)
{
    char *d;
    int n = 1;

    d = searchKeyData();
    if (d != NULL)
	n = atoi(d);
    return n * PREC_NUM;
}

void
deleteFiles()
{
    Buffer *buf;
    char *f;

    for (CurrentTab = FirstTab; CurrentTab; CurrentTab = CurrentTab->nextTab) {
	while (Firstbuf && Firstbuf != NO_BUFFER) {
	    buf = Firstbuf->nextBuffer;
	    discardBuffer(Firstbuf);
	    Firstbuf = buf;
	}
    }
    while ((f = popText(fileToDelete)) != NULL)
	unlink(f);
}

void
w3m_exit(int i)
{
#ifdef USE_MIGEMO
    init_migemo();		/* close pipe to migemo */
#endif
    deleteFiles();
#ifdef USE_SSL
    free_ssl_ctx();
#endif
    exit(i);
}

void
execCmd(void)
{
    char *data, *p;
    int cmd;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    data = searchKeyData();
    if (data == NULL || *data == '\0') {
	data = inputStrHist("command [; ...]: ", "", TextHist);
	if (data == NULL) {
	    displayBuffer(Currentbuf, B_NORMAL);
	    return;
	}
    }
    /* data: FUNC [DATA] [; FUNC [DATA] ...] */
    while (*data) {
	SKIP_BLANKS(data);
	if (*data == ';') {
	    data++;
	    continue;
	}
	p = getWord(&data);
	cmd = getFuncList(p);
	if (cmd < 0)
	    break;
	p = getQWord(&data);
	CurrentKey = -1;
	CurrentKeyData = NULL;
	CurrentCmdData = *p ? p : NULL;
#ifdef USE_MOUSE
	if (use_mouse)
	    mouse_inactive();
#endif
	w3mFuncList[cmd].func();
#ifdef USE_MOUSE
	if (use_mouse)
	    mouse_active();
#endif
	CurrentCmdData = NULL;
    }
    displayBuffer(Currentbuf, B_NORMAL);
}

#ifdef USE_ALARM
static MySignalHandler
SigAlarm(SIGNAL_ARG)
{
    char *data;

    if (alarm_sec > 0) {
	CurrentKey = -1;
	CurrentKeyData = NULL;
	CurrentCmdData = data = (char *)alarm_event.user_data;
#ifdef USE_MOUSE
	if (use_mouse)
	    mouse_inactive();
#endif
	w3mFuncList[alarm_event.cmd].func();
#ifdef USE_MOUSE
	if (use_mouse)
	    mouse_active();
#endif
	CurrentCmdData = NULL;
	onA();
	if (alarm_status == AL_EXPLICIT) {
	    disp_message_nsec(Sprintf("%s %s", w3mFuncList[alarm_event.cmd].id,
				      data ? data : "")->ptr,
			      FALSE, alarm_sec - 1, FALSE, TRUE);
	}
	else if (alarm_status == AL_IMPLICIT) {
	    alarm_buffer = Currentbuf;
	    alarm_status = AL_IMPLICIT_DONE;
	}
	else if ((alarm_status == AL_IMPLICIT_DONE
		  && alarm_buffer != Currentbuf)
		 || alarm_status == AL_IMPLICIT_ONCE) {
	    setAlarmEvent(0, AL_UNSET, FUNCNAME_nulcmd, NULL);
	}
	if (alarm_sec > 0) {
	    signal(SIGALRM, SigAlarm);
	    alarm(alarm_sec);
	}
    }
    SIGNAL_RETURN;
}

void
setAlarm(void)
{
    char *data;
    int sec = 0, cmd = -1;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    data = searchKeyData();
    if (data == NULL || *data == '\0') {
	data = inputStrHist("(Alarm)sec command: ", "", TextHist);
	if (data == NULL) {
	    displayBuffer(Currentbuf, B_NORMAL);
	    return;
	}
    }
    if (*data != '\0') {
	sec = atoi(getWord(&data));
	if (sec > 0)
	    cmd = getFuncList(getWord(&data));
    }
    if (cmd >= 0) {
	data = getQWord(&data);
	setAlarmEvent(sec, AL_EXPLICIT, cmd, data);
	disp_message_nsec(Sprintf("%s %s", w3mFuncList[cmd].id, data)->ptr,
			  FALSE, sec - 1, FALSE, TRUE);
    }
    else {
	setAlarmEvent(0, AL_UNSET, FUNCNAME_nulcmd, NULL);
    }
    displayBuffer(Currentbuf, B_NORMAL);
}

void
setAlarmEvent(int sec, short status, int cmd, void *data)
{
    if (status == AL_UNSET || status == AL_EXPLICIT
	|| status == AL_IMPLICIT_ONCE
	|| (status == AL_IMPLICIT && alarm_status != AL_EXPLICIT)) {
	alarm_sec = sec;
	alarm_status = status;
	alarm_event.cmd = cmd;
	alarm_event.user_data = data;
    }
}
#endif

void
reinit()
{
    char *resource = searchKeyData();

    if (resource == NULL) {
	init_rc(config_filename);
#ifdef USE_COOKIE
	initCookie();
#endif
	initKeymap(TRUE);
#ifdef USE_MENU
	initMenu();
#endif
	return;
    }

    if (!strcasecmp(resource, "CONFIG") || !strcasecmp(resource, "RC")) {
	init_rc(config_filename);
	return;
    }

#ifdef USE_COOKIE
    if (!strcasecmp(resource, "COOKIE")) {
	initCookie();
	return;
    }
#endif

    if (!strcasecmp(resource, "KEYMAP")) {
	initKeymap(TRUE);
	return;
    }

    if (!strcasecmp(resource, "MAILCAP")) {
	initMailcap();
	return;
    }

#ifdef USE_MENU
    if (!strcasecmp(resource, "MENU")) {
	initMenu();
	return;
    }
#endif

    if (!strcasecmp(resource, "MIMETYPES")) {
	initMimeTypes();
	return;
    }

#ifdef USE_EXTERNAL_URI_LOADER
    if (!strcasecmp(resource, "URIMETHODS")) {
	initURIMethods();
	return;
    }
#endif

    disp_err_message(Sprintf("Don't know how to reinitialize '%s'", resource)->
		     ptr, FALSE);
}

void
defKey(void)
{
    char *data;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    data = searchKeyData();
    if (data == NULL || *data == '\0') {
	data = inputStrHist("Key definition: ", "", TextHist);
	if (data == NULL || *data == '\0') {
	    displayBuffer(Currentbuf, B_NORMAL);
	    return;
	}
    }
    setKeymap(allocStr(data, -1), -1, TRUE);
    displayBuffer(Currentbuf, B_NORMAL);
}

TabBuffer *
newTab(void)
{
    TabBuffer *n;

    n = New(TabBuffer);
    if (n == NULL)
        return NULL;
    n->nextTab = NULL;
    n->currentBuffer = NULL;
    n->firstBuffer = NULL;
    return n;
}

static void
_newT(void)
{
    TabBuffer *tag;
    Buffer *buf;
    int i;

    tag = newTab();
    if (! tag)
	return;

    buf = newBuffer(Currentbuf->width);
    copyBuffer(buf, Currentbuf);
    buf->nextBuffer = NULL;
    for (i = 0; i < MAX_LB; i++)
	buf->linkBuffer[i] = NULL;
    (*buf->clone)++;
    tag->firstBuffer = tag->currentBuffer = buf;

    tag->nextTab = CurrentTab->nextTab;
    tag->prevTab = CurrentTab;
    if (CurrentTab->nextTab)
	CurrentTab->nextTab->prevTab = tag;
    else
	LastTab = tag;
    CurrentTab->nextTab = tag;
    CurrentTab = tag;
    nTab++;
}

void
newT(void)
{
    _newT();
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

TabBuffer *
numTab(int n)
{
    TabBuffer *tab;
    int i;

    if (n == 0)
	return CurrentTab;
    if (n == 1)
	return FirstTab;
    if (nTab <= 1)
	return NULL;
    for (tab = FirstTab, i = 1; tab && i < n; tab = tab->nextTab, i++)
	;
    return tab;
}

TabBuffer *
deleteTab(TabBuffer *tab)
{
    Buffer *buf, *next;

    if (nTab <= 1)
	return FirstTab;
    if (tab->prevTab) {
	if (tab->nextTab)
	    tab->nextTab->prevTab = tab->prevTab;
	else
	    LastTab = tab->prevTab;
	tab->prevTab->nextTab = tab->nextTab;
	if (tab == CurrentTab)
	    CurrentTab = tab->prevTab;
    }
    else {	/* tab == FirstTab */
	tab->nextTab->prevTab = NULL;
	FirstTab = tab->nextTab;
	if (tab == CurrentTab)
	    CurrentTab = tab->nextTab;
    }
    nTab--;
    buf = tab->firstBuffer;
    while (buf && buf != NO_BUFFER) {
	next = buf->nextBuffer;
	discardBuffer(buf);
	buf = next;
    }
    return FirstTab;
}

void
closeT(void)
{
    TabBuffer *tab;

    if (nTab <= 1)
	return;
    if (prec_num)
	tab = numTab(PREC_NUM);
    else
	tab = CurrentTab;
    if (tab)
	deleteTab(tab);
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

void
nextT(void)
{
    int i;

    if (nTab <= 1)
	return;
    for (i = 0; i < PREC_NUM; i++) {
	if (CurrentTab->nextTab)
	    CurrentTab = CurrentTab->nextTab;
	else
	    CurrentTab = FirstTab;
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

void
prevT(void)
{
    int i;

    if (nTab <= 1)
	return;
    for (i = 0; i < PREC_NUM; i++) {
	if (CurrentTab->prevTab)
	    CurrentTab = CurrentTab->prevTab;
	else
	    CurrentTab = LastTab;
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

void
followTab(TabBuffer *tab)
{
    Buffer *buf;
    Anchor *a;
 
#ifdef USE_IMAGE
    a = retrieveCurrentImg(Currentbuf);
    if (! (a && a->image && a->image->map))
#endif
	a = retrieveCurrentAnchor(Currentbuf);
    if (a == NULL)
	return;

    if (tab == CurrentTab) {
	check_target = FALSE;
	followA();
	check_target = TRUE;
	return;
    }
    _newT();
    buf = Currentbuf;
    check_target = FALSE;
    followA();
    check_target = TRUE;
    if (tab == NULL) {
	if (buf != Currentbuf)
	    delBuffer(buf);
	else
	    deleteTab(CurrentTab);
    }
    else if (buf != Currentbuf) {
	/* buf <- p <- ... <- Currentbuf = c */
	Buffer *c, *p;

	c = Currentbuf;
	p = prevBuffer(c, buf);
	p->nextBuffer = NULL;
	Firstbuf = buf;
	deleteTab(CurrentTab);
	CurrentTab = tab;
	for (buf = p; buf; buf = p) {
	    p = prevBuffer(c, buf);
	    pushBuffer(buf);
	}
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

void
tabA(void)
{
    followTab(prec_num ? numTab(PREC_NUM) : NULL);
}

static void
tabURL0(TabBuffer *tab, char *prompt, int relative)
{
    Buffer *buf;

    if (tab == CurrentTab) {
	goURL0(prompt, relative);
	return;
    }
    _newT();
    buf = Currentbuf;
    goURL0(prompt, relative);
    if (tab == NULL) {
	if (buf != Currentbuf)
	    delBuffer(buf);
	else
	    deleteTab(CurrentTab);
    }
    else if (buf != Currentbuf) {
	/* buf <- p <- ... <- Currentbuf = c */
	Buffer *c, *p;

	c = Currentbuf;
	p = prevBuffer(c, buf);
	p->nextBuffer = NULL;
	Firstbuf = buf;
	deleteTab(CurrentTab);
	CurrentTab = tab;
	for (buf = p; buf; buf = p) {
	    p = prevBuffer(c, buf);
	    pushBuffer(buf);
	}
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

void
tabURL(void)
{
    tabURL0(prec_num ? numTab(PREC_NUM) : NULL,
	    "Goto URL on new tab: ", FALSE);
}

void
tabrURL(void)
{
    tabURL0(prec_num ? numTab(PREC_NUM) : NULL,
	    "Goto relative URL on new tab: ", TRUE);
}

void
moveTab(TabBuffer *t, TabBuffer *t2, int right)
{
    if (!t || !t2 || t == t2)
	return;
    if (t->prevTab) {
	if (t->nextTab)
	    t->nextTab->prevTab = t->prevTab;
	else
	    LastTab = t->prevTab;
	t->prevTab->nextTab = t->nextTab;
    }
    else {
	t->nextTab->prevTab = NULL;
	FirstTab = t->nextTab;
    }
    if (right) {
	t->nextTab = t2->nextTab;
	t->prevTab = t2;
	if (t2->nextTab)
	    t2->nextTab->prevTab = t;
	else
	    LastTab = t;
 	t2->nextTab = t;
    }
    else {
	t->prevTab = t2->prevTab;
	t->nextTab = t2;
	if (t2->prevTab)
	    t2->prevTab->nextTab = t;
	else
	    FirstTab = t;
 	t2->prevTab = t;
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}

void
tabR(void)
{
    TabBuffer *tab;
    int i;

    for (tab = CurrentTab, i = 0; tab && i < PREC_NUM; tab = tab->nextTab, i++)
	;
    moveTab(CurrentTab, tab ? tab : LastTab, TRUE);
}

void
tabL(void)
{
    TabBuffer *tab;
    int i;

    for (tab = CurrentTab, i = 0; tab && i < PREC_NUM; tab = tab->prevTab, i++)
	;
    moveTab(CurrentTab, tab ? tab : FirstTab, FALSE);
}