home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume20 / reactivekbd / part02 / parse_keys.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-10-16  |  15.0 KB  |  798 lines

  1.  
  2. #include "file+rk.h"
  3. #include "functions.h"
  4. #include <stdio.h>
  5. #include <sys/ioctl.h>
  6. #include <ctype.h>
  7.  
  8. #define MAXKEYLEN 19
  9. #define MAXTOKEN  30
  10. #define UPCASE(c) (islower(c)?toupper(c):c)
  11.  
  12. #define UPCASE(c) (islower(c)?toupper(c):c)
  13. #define KEYWORDS (sizeof(functions)/sizeof(struct func))
  14. #define isodigit(c) ((isdigit(c))&&(c<'8'))
  15.  
  16. FILE *filedesc;
  17. char *key_file;
  18.  
  19. extern int (*keymap[128][MAXEXTENSIONS])();
  20. extern char meta_prefixes[MAXEXTENSIONS][MAXEXTENSIONS];
  21. extern int  meta_map[MAXEXTENSIONS][MAXEXTENSIONS];
  22. extern char next_free_map;
  23. extern char tc_ent[1024], tc_seq_buf[1024];
  24. extern struct sgttyb   new_stdin, old_stdin;
  25.  
  26. char *tgetstr();
  27. struct func {
  28.     char *name;
  29.     int (*address)();
  30.     char *description;
  31. } functions[]=
  32.     {
  33.         {"BOGUS",
  34.           BOGUS,
  35.          "Null routine, beeps terminal bell"},
  36.  
  37.         {"accept_forward_char",
  38.           accept_forward_char,
  39.          "Accept the next predicted character"},
  40.  
  41.         {"accept_forward_word",
  42.           accept_forward_word,
  43.          "Accept the next predicted word"},
  44.  
  45.         {"accept_to_end_of_line",
  46.           accept_to_end_of_line,
  47.          "Accept the whole predicted line"},
  48.  
  49.         {"backspace_char",
  50.           backspace_char,
  51.          "Backspace a single character"},
  52.  
  53.         {"backspace_word",
  54.           backspace_word,
  55.          "Backspace a single word"},
  56.  
  57.         {"backward_char",
  58.           backward_char,
  59.          "Go backwards a single character"},
  60.  
  61.         {"backward_paren",
  62.           backward_paren,
  63.          "Go backwards to matching parenthesis \"(\""},
  64.  
  65.         {"backward_word",
  66.           backward_word,
  67.          "Go backwards a single word"},
  68.  
  69.         {"beginning_of_line",
  70.           beginning_of_line,
  71.          "Move to the beginning of the line"},
  72.  
  73.         {"bogus",
  74.           BOGUS,
  75.          "Null routine, beeps terminal bell"},
  76.  
  77.         {"capitalize_word",
  78.           capitalize_word,
  79.          "Capitalize this word"},
  80.  
  81.         {"clear_display",
  82.           clear_display,
  83.          "Clear the screen and redraw the line"},
  84.  
  85.         {"close_paren",
  86.           close_paren,
  87.          "Close and show matching parenthesis"},
  88.  
  89.         {"command_completion",
  90.           command_completion,
  91.          "Expand a command using $PATH"},
  92.  
  93.         {"dash_to_ul_word",
  94.           dash_to_ul_word,
  95.          "Convert -'s to _'s in this word"},
  96.  
  97.         {"delete_char",
  98.           delete_char,
  99.          "Delete a single character"},
  100.  
  101.         {"delete_region_to_killbuffer",
  102.           delete_region_to_killbuffer,
  103.          "Delete marked region to killbuffer"},
  104.  
  105.         {"delete_word",
  106.           delete_word,
  107.          "Delete a single word"},
  108.  
  109.         {"describe_arguments",
  110.           describe_arguments,
  111.          "Show the current command line arguments"},
  112.  
  113.         {"describe_bindings",
  114.           describe_bindings,
  115.          "Show the current key bindings"},
  116.  
  117.         {"discard_current_edit_line",
  118.           discard_current_edit_line,
  119.          "Delete this line and forget it"},
  120.  
  121.         {"discard_rest_of_line",
  122.           discard_rest_of_line,
  123.          "Delete rest of line to killbuffer"},
  124.  
  125.         {"end_of_line",
  126.           end_of_line,
  127.          "Move to the end of the line"},
  128.  
  129.         {"file_completion",
  130.           file_completion,
  131.          "Expand pathname from the current prefix"},
  132.  
  133.         {"finish_editing_line",
  134.           finish_editing_line,
  135.          "Enter this line"},
  136.  
  137.         {"forward_char",
  138.           forward_char,
  139.          "Go forward a single character"},
  140.  
  141.         {"forward_paren",
  142.           forward_paren,
  143.          "Move to matching close parenthesis \")\""},
  144.  
  145.         {"forward_word",
  146.           forward_word,
  147.          "Go forward a single word"},
  148.  
  149.         {"increment_universal_argument",
  150.           increment_universal_argument,
  151.          "Do the next command 4^(presses) times"},
  152.  
  153.         {"insert_interrupt_char",
  154.           insert_interrupt_char,
  155.          "Send an interrupt character"},
  156.  
  157.         {"insert_quit_char",
  158.           insert_quit_char,
  159.          "Send a quit character"},
  160.  
  161.         {"insert_start_char",
  162.           insert_start_char,
  163.          "Send a start character"},
  164.  
  165.         {"insert_stop_char",
  166.           insert_stop_char,
  167.          "Send a stop character"},
  168.  
  169.         {"insert_suspend_char",
  170.           insert_suspend_char,
  171.          "Send a suspend character"},
  172.  
  173.         {"lowercase_word",
  174.           lowercase_word,
  175.          "Lowercase this word"},
  176.  
  177.         {"next_line",
  178.           next_line,
  179.          "Show the next line buffer"},
  180.  
  181.         {"next_pred",
  182.           next_pred,
  183.          "Show next alternative prediction"},
  184.  
  185.         {"null",
  186.           BOGUS,
  187.          "Null routine, beeps terminal bell"},
  188.  
  189.         {"open_paren",
  190.           open_paren,
  191.          "Open and show matching parenthesis"},
  192.  
  193.         {"previous_line",
  194.           previous_line,
  195.          "Show the previous line buffer"},
  196.  
  197.         {"previous_pred",
  198.           previous_pred,
  199.          "Show the previous alternative prediction"},
  200.  
  201.         {"prime_from_file",
  202.           prime_from_file,
  203.          "Prime the predictions from a file"},
  204.  
  205.         {"quote_char",
  206.           quote_char,
  207.          "Literally insert the next character"},
  208.  
  209.         {"run_mesg",
  210.           run_mesg,
  211.          "Run the mesg command"},
  212.  
  213.         {"run_ruptime",
  214.           run_ruptime,
  215.          "Run the ruptime command"},
  216.  
  217.         {"run_talk",
  218.           run_talk,
  219.          "Run the talk command"},
  220.  
  221.         {"run_tty_program",
  222.           run_tty_program,
  223.          "Run a program with rk turned off"},
  224.  
  225.         {"run_write",
  226.           run_write,
  227.          "Run the write command"},
  228.  
  229.         {"self_insert",
  230.           self_insert,
  231.          "Literally insert the current character"},
  232.  
  233.         {"set_mark",
  234.           set_mark,
  235.          "Set mark at the current cursor position"},
  236.  
  237.         {"show_free_nodes",
  238.           show_free_nodes,
  239.          "Show memory usage info for debugging"},
  240.  
  241.         {"show_mark",
  242.           show_mark,
  243.          "Show the position of the current mark"},
  244.  
  245.         {"show_version",
  246.           show_version,
  247.          "Show the current version number and date"},
  248.  
  249.         {"toggle_add_space_mode",
  250.           toggle_add_space_mode,
  251.          "Toggle add_space_mode (see manual)"},
  252.  
  253.         {"toggle_eol_longer_mode",
  254.           toggle_eol_longer_mode,
  255.          "Toggle eol_longer_mode (see manual)"},
  256.  
  257.         {"toggle_eol_only_mode",
  258.           toggle_eol_only_mode,
  259.          "Toggle eol_only_mode (see manual)"},
  260.  
  261.         {"toggle_lisp_mode",
  262.           toggle_lisp_mode,
  263.          "Toggle lisp_mode (see manual)"},
  264.  
  265.         {"toggle_nl_truncate_mode",
  266.           toggle_nl_truncate_mode,
  267.          "Toggle nl_truncate_mode (see manual)"},
  268.  
  269.         {"toggle_pred_mode",
  270.           toggle_pred_mode,
  271.          "Turn prediction display off or on"},
  272.  
  273.         {"toggle_show_eol_mode",
  274.           toggle_show_eol_mode,
  275.          "Toggle display of ^J at end of line"},
  276.  
  277.         {"twiddle_chars",
  278.           twiddle_chars,
  279.          "Exchange previous two characters"},
  280.  
  281.         {"ul_to_dash_word",
  282.           ul_to_dash_word,
  283.          "Convert _'s to -'s in this word"},
  284.  
  285.         {"uppercase_word",
  286.           uppercase_word,
  287.          "Uppercase this word"},
  288.  
  289.         {"yank_from_kill_buffer",
  290.           yank_from_kill_buffer,
  291.          "Insert text stored in killbuffer"}
  292.     };
  293.  
  294.  
  295. struct list {
  296.     char *key;
  297.     struct list *next;
  298. } *bindings[sizeof(functions)/sizeof(struct func)];
  299.  
  300.  
  301.  
  302. /***********************************\
  303. *                     *
  304. *  binary search from K&R "C" book  *
  305. *                     *
  306. \***********************************/
  307.  
  308. bsearch(s)
  309. char *s;
  310. {
  311.     int low, high, mid, cond;
  312.     low=0;
  313.     high= KEYWORDS-1;
  314.     while( low<= high) {
  315.         mid = (low+high)/2;
  316.         if( (cond = strcmp(s,functions[mid].name)) < 0)
  317.             high=mid-1;
  318.         else if (cond>0)
  319.             low=mid+1;
  320.         else
  321.             return(mid);
  322.     }
  323.     return(-1);
  324. }
  325.  
  326. parse_command()
  327. {
  328.     int x=1;
  329.     int number;
  330.     char c;
  331.     char token[MAXTOKEN];
  332.  
  333.  
  334.     while(isspace(c=fgetc(filedesc)));
  335.     
  336.     token[0]=c;
  337.  
  338.     while((isalpha(c=fgetc(filedesc)) || (c=='_'))&& (x<=MAXTOKEN))
  339.         token[x++]=c;
  340.  
  341.     token[x]=0;
  342.     if (c==EOF) return(-1);
  343.  
  344.     if ((!isspace(c)) && (c!=EOF)){
  345.         printf("Unexpected character '%c', Expecting whitespace or EOF.\n",c);
  346.         return(-1);
  347.     }
  348.     if(x>MAXTOKEN){
  349.         printf("Function name too long: '%s'\n",token);
  350.         return(-1);
  351.     }
  352.     number=bsearch(token);
  353.     if(number==-1)
  354.         printf("Function not found: %s\n",token);
  355.     return(number);
  356. }
  357.  
  358.  
  359. char get_cntl()
  360. {
  361.     int c=fgetc(filedesc);
  362.     
  363.     if(c==' ') return(200); /* Can't use 0 */
  364.     else if(c==EOF){
  365.         printf("Unexpected EOF\n");
  366.         return(200);
  367.     }else return(UPCASE(c)-'@');
  368. }
  369.  
  370. char parse_cntl(key)
  371. char key;
  372. {
  373.     if(key==0) abortit("Invalid ^ in key binding.\n",-1);
  374.     if(key==' ') return(0);
  375.     else return(UPCASE(key)-'@');
  376. }
  377.  
  378.  
  379. char get_slash()
  380. {
  381.  
  382.     int c=fgetc(filedesc);
  383.     int code=0;
  384.  
  385.     if(isodigit(c)){
  386.         while(isodigit(c)){
  387.             if((256-(c-='0'))<code){
  388.                 printf("Character Overflow\n");
  389.                 return(code);
  390.             }
  391.             code=(code<<3)+c;
  392.             c=fgetc(filedesc);
  393.         }
  394.         ungetc(c,filedesc);
  395.         return((char)code);
  396.     }
  397.     else if(c=='E')
  398.         return(27);
  399.     else if(c=='n')
  400.         return('\n');
  401.     else if(c=='r')
  402.         return('\r');
  403.     else if(c=='t')
  404.         return('\t');
  405.     else if(c=='b')
  406.         return('\b');
  407.     else if(c=='f')
  408.         return('\f');
  409.     else return(c);
  410. }    
  411.  
  412. char parse_slash(key)
  413. char **key;
  414. {
  415.  
  416.     int c=(*key)[0];
  417.     int code=0;
  418.  
  419.     (*key)++;
  420.     if(c==0) abortit("Invalid \\ in key binding.\n",-1);
  421.         
  422.     if(isodigit(c)){
  423.         while(isodigit(c)){
  424.             if((256-(c-='0'))<code){
  425.                 printf("Character Overflow\n");
  426.                 return(code);
  427.             }
  428.             code=(code<<3)+c;
  429.             c=(*key)[0];
  430.             (*key)++;
  431.         }
  432.         (*key)--;
  433.         return((char)code);
  434.     }
  435.     else if(c=='E')
  436.         return(27);
  437.     else if(c=='n')
  438.         return('\n');
  439.     else if(c=='r')
  440.         return('\r');
  441.     else if(c=='t')
  442.         return('\t');
  443.     else if(c=='b')
  444.         return('\b');
  445.     else if(c=='f')
  446.         return('\f');
  447.     else return(c);
  448. }    
  449.     
  450.  
  451. char *parse_key(key)
  452. char *key;
  453. {
  454.     static char ret_key[20];
  455.     int  x=0;
  456.     int  retval;
  457.     char c;
  458.  
  459.     while(((c=key[0])!='\0') && (x<=MAXKEYLEN)){
  460.         if(c=='\\'){
  461.             key++;
  462.             ret_key[x++]=parse_slash(&key);
  463.         }
  464.         else if(c=='^'){
  465.             ret_key[x++]=parse_cntl(key[1]);
  466.             key+=2;
  467.         }        
  468.         else{
  469.             ret_key[x++]=c;
  470.             key++;
  471.         }
  472.     }
  473.     ret_key[x]=0;
  474.  
  475.     if(x>MAXKEYLEN){
  476.         printf("Key too long.\n");
  477.         return((char *)-1);
  478.     }
  479.     return(ret_key);
  480. }
  481.  
  482. char *parse_termcap_key(key)
  483. char *key;
  484. {
  485.     char *term_key;
  486.     char term_cap[3];    
  487.     char *key_ptr;
  488.     
  489.  
  490.     term_key = tc_seq_buf;
  491.     key_ptr=tgetstr(key,&term_key);
  492.     if(!key_ptr){
  493.         printf("Unavailable Terminal Capability: %s\n",term_cap);
  494.         return((char *) -1);
  495.     }else
  496.         return(key_ptr); 
  497. }
  498.  
  499. char *get_key(buffer)
  500. char *buffer;
  501. {
  502.     static char key[20];
  503.     char *term_key;
  504.     char *key_ptr;
  505.     char term_cap[3];    
  506.     int  x=0;
  507.     int  c;
  508.     int  retval;
  509.     
  510.     while(isspace(c=fgetc(filedesc)));
  511.     if (c!='"'){
  512.         term_cap[0]=c;
  513.         term_cap[1]=fgetc(filedesc);
  514.         term_cap[2]=0;
  515.         term_key = tc_seq_buf;
  516.         key_ptr=tgetstr(term_cap,&term_key);
  517.         if(!key_ptr){
  518.             printf("Unavailable Terminal Capability: %s\n",term_cap);
  519.             return((char *) -1);
  520.         }
  521.         else{
  522.             strcpy(buffer,term_cap);
  523.             return(key_ptr);
  524.         }
  525.     }
  526.  
  527.     while(((c=fgetc(filedesc))!='\"') && (c!=EOF) 
  528.             && (x<=MAXKEYLEN)){
  529.         if(c=='\\') key[x++]=get_slash();
  530.         else if(c=='^') key[x++]=get_cntl();
  531.         else key[x++]=c;
  532.     }
  533.     key[x]=0;
  534.  
  535.     if(x>MAXKEYLEN){
  536.         printf("Key too long.\n");
  537.         return((char *)-1);
  538.     }
  539.     strcpy(buffer,key);
  540.     return(key);
  541. }
  542.  
  543. /***************************************************************************\
  544. *                                         *
  545. * Find the length of a string but count control chars as two so the length  *
  546. * of something like ^C is right                            *
  547. *                                         *
  548. \***************************************************************************/
  549. Strlen(str)
  550. char *str;
  551. {
  552.     register int len=0;
  553.     while(*str){
  554.         if((*str<32) || (*str==127))
  555.             len++;
  556.         len++;
  557.         str++;
  558.     }
  559.     return(len);
  560. }
  561. /*****************************************************************\
  562. *                                   *
  563. * Copy from b to a but replace control chars with ^-char like ^C  *
  564. *                                   *
  565. \*****************************************************************/
  566. Strcpy(a,b)
  567. char *a,*b;
  568. {
  569.     while(*b){
  570.         if((*b<32) || (*b==127)){
  571.             *a++='^';
  572.             *a++=(*b==127)?b++,'?':(*b++)+'@';
  573.         }                
  574.         *a++ = *b++;
  575.     }
  576.     *a=0;
  577. }
  578.  
  579.  
  580. add_to_bindings(key,function)
  581. char *key;
  582. int (*function)();
  583. {
  584.     int x,found_it=0;
  585.     struct list *current,*previous;
  586.     char good_key[30];
  587.     Strcpy(good_key,key);
  588.  
  589.     for(x=0;x<sizeof(functions)/sizeof(struct func);x++){
  590.         current=bindings[x];
  591.         while(bindings[x]&&!strcmp(bindings[x]->key,good_key)){
  592.             current=bindings[x]->next;
  593.             free(bindings[x]);
  594.             bindings[x]=current;
  595.         }
  596.         while(current!=0){
  597.             if(!strcmp(current->key,good_key)){
  598.                 previous->next=current->next;
  599.                 free(current);
  600.             }
  601.             previous=current;
  602.             current=current->next;
  603.         }
  604.  
  605.     }
  606.     for(x=0;x<sizeof(functions)/sizeof(struct func);x++){
  607.         if(function==functions[x].address){
  608.             found_it=1;
  609.             break;
  610.         }
  611.     }
  612.     if(found_it){
  613.         if(bindings[x]==0){
  614.             bindings[x]=(struct list *)malloc(sizeof(struct list));
  615.             bindings[x]->key=malloc(Strlen(key)+1);
  616.             Strcpy(bindings[x]->key,key);
  617.             bindings[x]->next=0;
  618.         } else {
  619.             current=bindings[x];
  620.             while(current->next != 0)
  621.                 current=current->next;
  622.             current->next=(struct list *)malloc(sizeof(struct list));
  623.             current->next->key=malloc(Strlen(key)+1);
  624.             Strcpy(current->next->key,key);
  625.             current->next->next=0;
  626.         }
  627.     }
  628. }            
  629.             
  630.  
  631.  
  632. bind_to_key(key,function)
  633. char *key;
  634. int (*function)();
  635. {
  636.     char *binary_key;    
  637.     
  638.     binary_key=parse_key(key);
  639.     if(binary_key!=(char *)-1){
  640.         add_to_bindings(key,function);
  641.         do_bind_to_key(binary_key,0,function);
  642.     }
  643. }
  644.  
  645. bind_termcap_key(key,function)
  646. char *key;
  647. int (*function)();
  648. {
  649.     char *binary_key;    
  650.     
  651.     binary_key=parse_termcap_key(key);
  652.     if(binary_key!=(char *)-1){
  653.         add_to_bindings(key,function);
  654.         do_bind_to_key(binary_key,0,function);
  655.     }
  656. }
  657.  
  658. do_bind_to_key(key,current_key_map,function)
  659. char *key;
  660. char  current_key_map;
  661. int (*function)();
  662. {
  663.     int x;
  664.  
  665.     
  666.     if((strlen(key)==1) || (strlen(key)==0)){
  667.         keymap[key[0]][current_key_map]=function;
  668.     } else {
  669.         for(x=0;(x<MAXEXTENSIONS)&&(meta_prefixes[x][current_key_map])&&
  670.             (key[0]!=meta_prefixes[x][current_key_map]);x++);
  671.         if(x==MAXEXTENSIONS){
  672.             abortit("Too many keymaps, aborting.\r\n",-1);
  673.         }else if(meta_prefixes[x][current_key_map]){
  674.             do_bind_to_key(key+1,meta_map[x][current_key_map],function);
  675.         }else {
  676.             meta_prefixes[x][current_key_map]=key[0];
  677.             meta_map[x][current_key_map]=next_free_map;
  678.             keymap[key[0]][current_key_map]=meta_prefix;
  679.             next_free_map++;
  680.             do_bind_to_key(key+1,next_free_map-1,function);
  681.             if(next_free_map==MAXEXTENSIONS)
  682.                 abortit("Too many keymaps, aborting.\r\n",-1);
  683.         }
  684.     }
  685. }
  686.  
  687.  
  688. get_key_bindings()
  689. {
  690.  
  691.     char *termname, *tbuf, *getenv();
  692.     int  function_num;
  693.     char *key;
  694.     char key_string[30];
  695.     int x;
  696.  
  697.     if ((filedesc=fopen(key_file,"r"))==0){
  698.         return;
  699.     }
  700.  
  701.     do{
  702.         function_num=parse_command();
  703.         if(function_num==-1)
  704.             break;
  705.         key=get_key(key_string);
  706.         if(key==(char *)-1)
  707.             break;
  708.         add_to_bindings(key_string,functions[function_num].address);
  709.         do_bind_to_key(key,0,functions[function_num].address);
  710.     } while(1);
  711.     fclose(filedesc);
  712. }
  713.  
  714. int
  715. describe_bindings(e)
  716.     ED_STRUCT      *e;
  717. {
  718.     void        (*sig)();
  719.     char    reply;
  720.     char    fname[100];    
  721.         
  722.     printf("\r\nSend to a file? (y/n)");
  723.     if((reply=getchar())=='Y' || reply == 'y'){
  724.         ioctl(0, TIOCGETP, &new_stdin);
  725.         ioctl(0, TIOCSETP, &old_stdin);
  726.         sig=signal(SIGCHLD,SIG_DFL); 
  727.         printf("\nFilename: ");
  728.         gets(fname);
  729.         show_bindings(fname);
  730.     }else{
  731.         ioctl(0, TIOCGETP, &new_stdin);
  732.         ioctl(0, TIOCSETP, &old_stdin);
  733.         sig=signal(SIGCHLD,SIG_DFL); 
  734.         fname[0]=0;    
  735.         show_bindings(0);
  736.     }    
  737.     signal(SIGCHLD,sig); 
  738.     ioctl(0, TIOCSETP, &new_stdin);
  739.     write(1, "Continue: ", 10);
  740.     draw_current_edit_line(e);
  741. }
  742.  
  743.  
  744. show_bindings(fname)
  745.     char *fname;
  746. {
  747.     int x;
  748.     struct list *current;
  749.     char *more;
  750.     FILE *pipe;
  751.  
  752.     if(!fname)    
  753.         if((more=getenv("PAGER"))==0){
  754.             if((pipe=popen("more","w"))==0){
  755.                 perror("more");
  756.                 return;
  757.             }
  758.         } else {
  759.             if((pipe=popen(more,"w"))==0){
  760.                 perror(more);
  761.                 return;
  762.             }
  763.         }
  764.     else
  765.         if((pipe=fopen(fname,"w"))==0){
  766.             perror(fname);
  767.             return;
  768.         }
  769.     
  770.  
  771.  
  772.     fprintf(pipe,"\n         FUNCTION NAME       BOUND TO \tDESCRIPTION\n");
  773.     fprintf(pipe,"         -------- ----       ----- -- \t-----------\n");
  774.  
  775.     for(x=0;x<(sizeof(functions)/sizeof(struct func));x++){
  776.         if((functions[x].address==BOGUS)
  777.             || (functions[x].address==self_insert))
  778.             continue;
  779.         fprintf(pipe,"%28s",functions[x].name);
  780.         current=bindings[x];
  781.         if(current!=0){
  782.             fprintf(pipe,"%6s\t",current->key);
  783.             current=current->next;
  784.         } else {
  785.             fprintf(pipe,"      \t");
  786.         }
  787.         fprintf(pipe,"%s",functions[x].description);
  788.         while(current!=0){
  789.             fprintf(pipe,"\n%34s",current->key);
  790.             current=current->next;
  791.         }
  792.         fprintf(pipe,"\n");
  793.     }
  794.     pclose(pipe);
  795. }
  796.  
  797.  
  798.