home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / qtawk / display.doc < prev    next >
Text File  |  1990-11-12  |  29KB  |  764 lines

  1. # QTAwk "more" utility
  2. #
  3. # Display one screen of a file at a time
  4. #
  5. # Command Line Parameters Available: (Note: must precede on command line
  6. #   with "--" option to prevent QTAwk from trying to recognize)
  7. #   ansi = FALSE --> turn off use of ANSI.SYS display driver
  8. #   -ppath    --> use "path" to locate files to read
  9. #   +/r.e.[/] --> read first file until locate match to r.e. regular expression
  10. #
  11. #
  12. # "commands" allow user to:
  13. #   [Qq](uit)?       -> quit
  14. #   [Hh](elp)?       -> diplay help
  15. #   [Ff](ile)?       -> skip to next file
  16. #   [Rr](edraw)?   -> re-draw last screen
  17. #   [Nn](umbers)?  -> turn line numbers on/off
  18. #   [Tt](abs)?       -> turn tab substitution on/off
  19. #   [Cc](ontext)?  -> display search/match/highlight r.e.
  20. #   {_d}+       -> go to {_d} line, {_d} > current line number
  21. #   {_d}*l       -> skip {_d} lines
  22. #   {_d}*s       -> skip {_d} screens
  23. #   {_d}*/r/       -> go to {_d} next match of r.e.
  24. #   {_d}*m       -> go to {_d} next match of last r.e. entered as above
  25. #   {_d}*p       -> set number of lines prior to match to display
  26. #   {_d}*d       -> set display line length to {_d}, default 79
  27. #   h{_d}/r/       -> Highlight text matching r.e.
  28. #   a{_d}/r/s/       -> replace matching string
  29. #   [Ii](nit)?       -> re-initialize
  30. #              - line numbering
  31. #              - tab expansion
  32. #              - display line length
  33. #              - prior lines (to match)
  34. #              - search/highlight/replace patterns
  35. #     if optional {_d}* not entered - default to 1
  36. #
  37. # Use the getdir function to find files matching the patter(s) passed.
  38. # Patterns follow the wildcard syntax of DOS expanded to allow the use
  39. # of character classes, and to allow characters after the '*' wildcard.
  40. # Dos does not recognize characters following the '*'. Must also enclose
  41. # filename specifications in quotes, "fn", to prevent expansion by the QTAwk
  42. # wild card expansion routine. For example the DOS wildcard expression for
  43. # all file names starting with 'c' and ending with 't' or 'p' and with an
  44. # extension of "exp" would be:
  45. #   "c*[pt].exp"
  46. # this is translated into the regular expression syntax:
  47. #   /^C[!\X001-\X021."\/\\\[\]:|<>+=;,]*[PT]\.EXP$/
  48. #
  49. # Multiple patterns may also be specified:
  50. #   QTAwk -fmore.exp -- "[gdh]*.(hlp|txt)" "*(dir|bnc).exp"
  51. #
  52. #
  53. BEGIN {
  54.     local p_indx = 0;
  55.     local sub_dir = ""; # default to current sub-directory
  56.     local fnames;
  57.     local cnames, cindex = 0;
  58.     local ipat;
  59.     local i, j;
  60.  
  61.     # set the standard error file
  62.     stderr = "stderr";
  63.  
  64.     # set displayed line length
  65.     display_length = def_display_length = 79;
  66.  
  67.     # flag for expanding tabs
  68.     sub_tabs = FALSE;
  69.  
  70.     if ( ARGC == 1 ) {
  71.     cmd_help;
  72.     exit 1;
  73.     }
  74.  
  75.     init_sre = FALSE;
  76.  
  77.     # set the regular expressions for recognizing "commands"
  78.     Quit       = /^{_w}*[Qq](uit)?{_w}*$/;
  79.     Help       = /^{_w}*[Hh](elp)?{_w}*$/;
  80.     Re_display = /^{_w}*[Rr](edraw)?{_w}*$/;
  81.     Next_file  = /^{_w}*[Ff](ile)?{_w}*$/;
  82.     Numbersl   = /^{_w}*[Nn](umbers)?{_w}*$/;
  83.     Sub_Tabs   = /^{_w}*[Tt](abs)?{_w}*$/;
  84.     Review_P   = /^{_w}*[Cc](ontext)?{_w}*$/;
  85.     GoTo_line  = /^{_w}*{_d}+{_w}*$/;
  86.     Skip_lines = /^{_w}*{_d}*l{_w}*$/;
  87.     Skip_scrn  = /^{_w}*{_d}*s{_w}*$/;
  88.     Match_RE   = /^{_w}*{_d}*\//;
  89.     RE_reset   = /^{_w}*{_d}*m{_w}*$/;
  90.     Prior_cmd  = /^{_w}*{_d}*p{_w}*$/;
  91.     Display_L  = /^{_w}*{_d}*d{_w}*$/;
  92.     High_RE    = /^{_w}*h{_w}*{_d}*{_w}*\//;
  93.     Replace_RE = /^{_w}*r{_w}*{_d}*{_w}*\//;
  94.     Init_RE    = /^{_w}*[Ii](nit)?{_w}*$/;
  95.  
  96.     # set regular expressions for command line options
  97.     # must precede these on the command line to QTAwk with "--"
  98.     # to prevent QTAwk from recognizing
  99.     Set_path = /^-[Pp]/;
  100.     RE_cmd   = /^\+\//;
  101.  
  102.     # set regular expression for recognizing leading digits in a command
  103.     ldg_digits = /^{_w}*{_d}+/;
  104.  
  105.     # DOS filename wild card search pattern
  106.     wild_cards = /[\*\?]/;
  107.  
  108.     # specify legal filename characters by excluding those which are illegal
  109.     legal_chars = /[!\x001-\x021."\/\\\[\]:|<>+=;,]/;
  110.  
  111.     for ( i = 1 ; i < ARGC ; i++ ) {
  112.     ipat = ARGV[i];
  113.     switch ( ipat ) {
  114.         case Set_path:
  115.         sub(Set_path,"",ipat);
  116.         if ( length(ipat) == 0 ) ipat = ARGV[++i];
  117.         sub_dir ∩= ipat;
  118.         # check for trailing back-slash on path
  119.         if ( sub_dir !~ /\\$/ ) sub_dir ∩= '\\';
  120.         break;
  121.         case RE_cmd:
  122.         sub(/^\+/,"",ipat);
  123.         execute_cmd(ipat);
  124.         init_sre = TRUE;
  125.         break;
  126.         default:
  127.         #
  128.         # convert DOS filename wild card characters to appropriate regular
  129.         # expression operators and escape extension period to prevent
  130.         # interpretation as r.e. "any character" operator - other r.e.
  131.         # operators allowed.
  132.         #
  133.         ipat = strupr(ipat);
  134.         if ( ipat ~~ wild_cards ) {
  135.         gsub(/\./,"\\.",ipat);
  136.         gsub(/\*/,"{legal_chars}*",ipat);
  137.         gsub(/\?/,"{legal_chars}?",ipat);
  138.         #
  139.         # the following line will convert the command line strings
  140.         # into regular expressions. This is to prevent the constant
  141.         # conversion of a string into a regular expression in the
  142.         # "getdir" function.
  143.         #
  144.         execute("pattern[" ∩ ++p_indx ∩ "] = /^" ∩ ipat ∩ "$/;");
  145.         } else cnames[++cindex] = ARGV[i];
  146.         break;
  147.     }
  148.     }
  149.     # if you want to see the r.e. for the files un-comment the following line
  150. #    for ( i in pattern ) print "Searching For: " ∩ replace(pattern[i]);
  151.     # delete command line arguments - will replace with directory search below
  152.     while ( 1 in ARGV ) delete ARGV[1];
  153.     i = 1;
  154.     fsize_indx = 1;    # initialize index into file size array
  155.     file_sizea[0] = 0;
  156.     if ( cindex )
  157.     for ( cindex in cnames ) {
  158.         ipat = ARGV[i++] = cnames[cindex];
  159.         file_sizea[fsize_indx++] = get_size(ipat);
  160.     }
  161.     if ( p_indx ) {
  162.         #
  163.         # go find matching files and print names
  164.         #
  165. #     for ( i in pattern ) print "Searching For: " ∩ replace(pattern[i]);
  166.     fnames = getdir(sub_dir,pattern);
  167.     for ( j in fnames ) {
  168.         ARGV[i++] = sub_dir ∩ fnames[j];
  169.     }
  170.     }
  171.  
  172.     # check for NO directory entries which match - exit
  173.     # If do not exit, then QTAwk will read from Standard Input - with no
  174.     # prompt - it will appear as if the machine has hung. a Ctrl-Z will
  175.     # input an end-of-file and terminate, but user probably not expecting
  176.     # to have to do that
  177.     if ( i == 1 ) {
  178.     print "No Directory Entries Match filename Specifications";
  179.     exit;
  180.     }
  181.  
  182.     # set the number of command arguments
  183.     ARGC = i;
  184.  
  185.     # initialize index into file size array
  186.     fsize_indx = 1;
  187.  
  188.     # set number of lines on screen
  189.     screen_size = 25;
  190.  
  191.     # set number of lines to display prior to line matching r.e.
  192.     prior_lines = dprior_lines = 15;
  193.  
  194.     # NOTE: use '\x0ff' in ANSI sequences below. The '\x0ff' will get
  195.     # translated to '[' before being printed. Use '\x0ff' character
  196.     # so that '[' may be used in search and hihgh lighted text regular
  197.     # expressions without being substituted for. This assumes that
  198.     # the '\x0ff' character will probably not be in a search pattern
  199.     # or high lighted text pattern.
  200.     # set ANSI strings for text highlighting
  201.     ansi = TRUE; ### turn on use of ANSI.SYS display driver
  202.     Red_on_Black    = "\x01b\x0ff0;31;40m";
  203.     Green_on_Black  = "\x01b\x0ff0;32;40m";
  204.     Yellow_on_Black = "\x01b\x0ff0;33;40m";
  205.     Blue_on_Black   = "\x01b\x0ff0;34;40m";
  206.     Magenta_Black   = "\x01b\x0ff0;35;40m";
  207.     Cyan_Black        = "\x01b\x0ff0;36;40m";
  208.     White_Black     = "\x01b\x0ff0;37;40m";
  209.     Black_on_Red    = "\x01b\x0ff0;30;41m";
  210.     Green_on_Red    = "\x01b\x0ff0;32;41m";
  211.  
  212.     # set ANSI strings for text highlighting - bold text
  213.     Red_on_Blackh   = "\x01b\x0ff1;31;40m";
  214.     Green_on_Blackh = "\x01b\x0ff1;32;40m";
  215.     Yellow_on_Blackh= "\x01b\x0ff1;33;40m";
  216.     Blue_on_Blackh  = "\x01b\x0ff1;34;40m";
  217.     Magenta_Blackh  = "\x01b\x0ff1;35;40m";
  218.     Cyan_Blackh     = "\x01b\x0ff1;36;40m";
  219.     White_Blackh    = "\x01b\x0ff1;37;40m";
  220.     Black_on_Redh   = "\x01b\x0ff1;30;41m";
  221.     Green_on_Redh   = "\x01b\x0ff1;32;41m";
  222.  
  223.     # set array members for highlighting phrases
  224.     High_Text[1] = Red_on_Blackh;
  225.     High_Text[2] = Green_on_Blackh;
  226.     High_Text[3] = Yellow_on_Blackh;
  227.     High_Text[4] = Blue_on_Blackh;
  228.     High_Text[5] = Magenta_Blackh;
  229.     High_Text[6] = Cyan_Blackh;
  230.     High_Text[7] = White_Blackh;
  231.     High_Text[8] = Black_on_Redh;
  232.     High_Text[9] = Green_on_Redh;
  233.  
  234.     # set ANSI sequence for normal text
  235.     Normal  = White_on_Blue = "\x01b\x0ff0;37;44m";
  236.  
  237.     manual_high;
  238.  
  239.     blank_line = /^\f?{_w}*$/;
  240. }
  241.  
  242. INITIAL {
  243.     line_count = 1;
  244. #    matching_re_start = matching_re_length = 0;
  245.     searching_re = init_sre;
  246.     exit_endfile = init_sre = FALSE;
  247.     file_size = file_sizea[ARGI - 1];
  248.     amt_read = 0;
  249.     cls;
  250.     print "=====> " ∩ FILENAME ∩ " : " ∩ file_size ∩ " <=====";
  251. }
  252.  
  253. blank_line {
  254.     if ( !searching_re && !print_blank ) {
  255.     print_blank = TRUE;
  256.     print "";
  257.     ++line_count;
  258.     last_screen[row++] = "";
  259.     }
  260.     next;
  261. }
  262.  
  263.     {
  264.     local i;
  265.     local inp;
  266.     local hdr = line_numbers ? FNR ∩ ": " : "";
  267.     local ol = length;    # set to length of input line
  268.     local dl;
  269.  
  270.     print_blank = FALSE;
  271.     amt_read += ol + 2; # added 2 to size read to account for CR/LF
  272.     dl = hdr ∩ $0;
  273.     ol += length(dl);  # reset length of displayed line
  274.     # set line to be displayed, truncate to keep from overflowing display line
  275.     # will still overflow on some lines since tabs are counted as a single
  276.     # character here, but expanded by DOS on output to display. Could replace
  277.     # tabs with a single blank to prevent this from happening
  278.     if ( length(dl) > display_length ) dl = substr(dl,1,display_length);
  279.     if ( !searching_re ) {
  280.       # here when not searching for regular expression or have found
  281.       #
  282.       # check if translating horizontal tabs to blanks - do if TRUE
  283.     if ( sub_tabs ) dl = stran(dl,' ','\t');
  284.       # check if ANSI.SYS display driver being used
  285.     if ( ansi ) {
  286.           # If a search pattern exists - high-light
  287.         if ( Search_pat ) gsub(Search_pat,Red_on_Black ∩ "$$0" ∩ Normal,dl);
  288.           # put in high light ansi sequences for high lighted text
  289.         for ( i in High_pat ) gsub(High_pat[i],High_Text[i] ∩ "$$0" ∩ Normal,dl);
  290.           # replace matching strings
  291.         for ( i in Replace_pat ) gsub(Replace_pat[i][0],Replace_pat[i][1],dl);
  292.           # translate '\x0ff' character to '[' for ANSI sequences
  293.         dl = stran(dl,'[','\x0ff');
  294.       } else {
  295.         for ( i in Replace_pat ) gsub(Replace_pat[i][0],Replace_pat[i][1],dl);
  296.           # translate '\x0ff' character to '[' for ANSI sequences
  297.         dl = stran(dl,'[','\x0ff');
  298.     }
  299.     print dl;
  300.     # store display line
  301.     last_screen[row++] = $0;
  302.     # check if last line on screen
  303.     if ( ++line_count >= screen_size ) {
  304.         percent_rd = (int((1000.0 * amt_read)/file_size) + 5)/ 10;
  305.         while ( TRUE ) {
  306.         printf("%s : %u%%/%lu/%u <-> (Command - h for help)? Enter",FILENAME,percent_rd,file_size,FNR);
  307.         fgetline("stdin",inp);
  308.         if ( length(inp) > 0 ) {
  309.             execute_cmd(inp);
  310.             if ( break_loop ) {
  311.             break_loop = FALSE;
  312.             break;
  313.             }
  314.         } else break;
  315.         }
  316.         cls;
  317.         line_count = 1;
  318.         deletea last_screen;
  319.         row = 0;
  320.     }
  321.       } else if ( $0 ~~ Search_pat ) {
  322.     # here if found match in r.e. search
  323.     match_found++;
  324.     if ( !--searching_re ) {
  325. #         printf("xxxxxx : Match xxx/xxx    \r");
  326.         printf("                          \r");
  327.         row += line_count += re_draw(match_last);
  328.         last_screen = match_last;
  329.         cycle;
  330.       } else {
  331.         printf("%6u : Match: %3u/%3u\r",FNR,match_found,searching_re);
  332.         next;
  333.     }
  334.       } else {
  335.     # here if searching for r.e., but current line does not match
  336.     # 'rotate' storage array an tack current line on end
  337.     printf("%6u\r",FNR);
  338.     match_last[1] = $0;
  339.     rotate(match_last);
  340.     }
  341. }
  342.  
  343. FINAL {
  344.     for ( ++line_count ; ++line_count < screen_size ; ) print "";
  345.     print "=====> " ∩ FILENAME ∩ " <=====";
  346.     if ( !exit_endfile ) {
  347.     printf("%s <-> Press Enter",FILENAME);
  348.     fgetline("stdin",inp);
  349.     }
  350.     exit_endfile = FALSE;
  351. }
  352.  
  353. # function to check for valid command and execute
  354. function execute_cmd(cmd_str) {
  355.     local i, j;
  356.     local scrn_m = 1;
  357.     local digits = FALSE;
  358.  
  359.     # NOTE: If leading digits on command, find
  360.     #        add 0 to digits to convert to integer. Otherwise if only one
  361.     #        digit, "substr" function returns a character value. Incrementing
  362.     #        a character value with '++' operator gives next character in ASCII
  363.     #        sequence, decrementing with '--' gives previous character.
  364.     if ( cmd_str ~~ ldg_digits ) {
  365.     digits = substr(cmd_str,MSTART,MLENGTH) + 0;
  366.     cmd_str = strim(deletec(cmd_str,MSTART,MLENGTH));
  367.     }
  368.     if ( cmd_str ) switch ( cmd_str ) {
  369.     case Numbersl:
  370.         # toggle line numbering on/off
  371.         line_numbers = !line_numbers;
  372.         break;
  373.     case Help:
  374.         help;
  375.         break;
  376.     case GoTo_line:
  377.         if ( digits > FNR ) skip_ahead(digits - FNR - 1);
  378.         break_loop = TRUE;
  379.         break;
  380.     case Quit:
  381.         exit_endfile = TRUE;
  382.         exit;
  383.         break;
  384.     case Re_display:
  385.         cls;
  386.         re_draw(last_screen);
  387.         break;
  388.     case Next_file:
  389.         deletea last_screen;
  390.         exit_endfile = TRUE;
  391.         endfile;
  392.         break;
  393.     case Prior_cmd:
  394.         prior_lines = digits ? digits : dprior_lines;
  395.         deletea match_last;
  396.         break;
  397.     case Skip_scrn:
  398.         scrn_m = screen_size;
  399.     case Skip_lines:
  400.         skip_cnt = 1;
  401.         if ( digits ) skip_cnt = digits;
  402.         skip_ahead(skip_cnt * scrn_m);
  403.         break_loop = TRUE;
  404.         break;
  405.     case Match_RE:
  406.         if ( cmd_str !~ /\/$/ ) cmd_str ∩= '/';
  407.         execute("Search_pat = " ∩ cmd_str ∩ ";");
  408.     case RE_reset:
  409.         if ( Search_pat ) {
  410.         searching_re = digits ? digits : TRUE;
  411.         match_found = 0;
  412.         for ( j = prior_lines , i = 1 ; j ; i++ , j-- )
  413.           match_last[i] = last_screen[screen_size - j];
  414.         }
  415.         break_loop = TRUE;
  416.         break;
  417.     case High_RE:
  418.         cmd_str = deletec(cmd_str,1,1);
  419.         if ( cmd_str ~~ ldg_digits ) {
  420.         digits = substr(cmd_str,MSTART,MLENGTH) + 0;
  421.         cmd_str = strim(deletec(cmd_str,MSTART,MLENGTH));
  422.         if ( !digits ) digits = 1;
  423.         } else digits = 1;
  424.         if ( digits < 10 ) {
  425.         if ( cmd_str !~ /\/$/ ) cmd_str ∩= '/';
  426.         execute("High_pat[digits] = " ∩ cmd_str ∩ ";");
  427.         }
  428.         break;
  429.     case Review_P:
  430.         if ( Search_pat ) print "Search Pattern: /" ∩ Search_pat ∩ '/';
  431.         for ( i in High_pat ) print "High Lighted Pattern (" ∩ i ∩ "): /" ∩ High_pat[i] ∩ '/';
  432.         for ( i in Replace_pat ) {
  433.         print "Replace Pattern (" ∩ i ∩ "): /" ∩ Replace_pat[i][0] ∩ '/';
  434.         print "Replace String  (" ∩ i ∩ "): \"" ∩ Replace_pat[i][1] ∩ '"';
  435.         }
  436.         break;
  437.     case Display_L:
  438.         if ( digits ) display_length = digits;
  439.           else display_length = def_display_length;
  440.         break;
  441.     case Sub_Tabs:
  442.         sub_tabs = !sub_tabs;
  443.         break;
  444.     case Replace_RE:
  445.         cmd_str = deletec(cmd_str,1,1);
  446.         if ( cmd_str ~~ ldg_digits ) {
  447.         digits = substr(cmd_str,MSTART,MLENGTH) + 0;
  448.         cmd_str = strim(deletec(cmd_str,MSTART,MLENGTH));
  449.         if ( !digits ) digits = 1;
  450.         } else digits = 1;
  451.         if ( digits < 10 && cmd_str ~~ /\/[!\/]+\// ) {
  452.         i = substr(cmd_str,MSTART,MLENGTH);
  453.         cmd_str = substr(cmd_str,MSTART + MLENGTH);
  454.         sub(/\/$/,"",cmd_str);
  455.         execute("Replace_pat[digits][0] = " ∩ i ∩ ";");
  456.         execute("Replace_pat[digits][1] = \"" ∩ cmd_str ∩ "\";");
  457.         }
  458.         break;
  459.     case Init_RE:
  460.         deletea(High_pat);
  461.         deletea(Replace_pat);
  462.         display_length = def_display_length;
  463.         manual_high;
  464.         prior_lines = dprior_lines;
  465.         searching_re = line_numbers = sub_tabs = Search_pat = FALSE;
  466.         break;
  467.       } else if ( digits > FNR ) {
  468.     skip_ahead(digits - FNR - 1);
  469.     break_loop = TRUE;
  470.     }
  471. }
  472.  
  473. # function to redraw screen
  474. function re_draw(screen) {
  475.     local j = 0;
  476.     local k = 0;
  477.     local i, n;
  478.     local cl;
  479.  
  480.     for ( i in screen ) k++;
  481.     j = FNR - k + 1;
  482.     for ( i in screen ) {
  483.     cl = (line_numbers ? j++ ∩ ": " : "") ∩ screen[i];
  484.     if ( sub_tabs ) cl = stran(cl," ","\t");
  485.     if ( length(cl) > display_length ) cl = substr(cl,1,display_length);
  486.       # check if ANSI.SYS display driver being used
  487.     if ( ansi ) {
  488.         if ( Search_pat ) gsub(Search_pat,Red_on_Black ∩ "$$0" ∩ Normal,cl);
  489.         for ( n in High_pat ) gsub(High_pat[n],High_Text[n] ∩ "$$0" ∩ Normal,cl);
  490.         for ( n in Replace_pat ) gsub(Replace_pat[n][0],Replace_pat[n][1],cl);
  491.         cl = stran(cl,'[','\x0ff');
  492.       } else {
  493.         for ( n in Replace_pat ) gsub(Replace_pat[n][0],Replace_pat[n][1],cl);
  494.         cl = stran(cl,'[','\x0ff');
  495.     }
  496.     print cl;
  497.     }
  498.     return k;
  499. }
  500.  
  501. # function to skip ahead number of lines in current file specified
  502. function skip_ahead(lines) {
  503.     local dummy;
  504.  
  505.     cls;
  506.     while ( lines-- ) {
  507.     # read next line, check for input and not EOF
  508.     if ( getline(dummy) <= 0 ) {
  509.         exit_endfile = TRUE;
  510.         break;
  511.     }
  512.     # added 2 to size read to account for CR/LF
  513.     amt_read += length(dummy) + 2;
  514.     printf("%u\r",FNR);
  515.     }
  516. }
  517.  
  518. function help() {
  519.     local tabs = sub_tabs ? "ON" : "OFF";
  520.  
  521.     if ( ansi ) {
  522.     cls;
  523.     print "\x01b[1;32;40mMORE\x01b[0;37;44m File Function Commands";
  524.     print "Commands: (i stands for an integer matched by {_d}.)";
  525.     print "i* means the integer is optional  (match {_d}*) - 1 defaults.";
  526.     print "i+ means the integer is mandatory (match {_d}+) - no default.";
  527.     print "[\x01b[1;32;40mQq\x01b[0;37;44m](uit)?    -> exit to DOS.";
  528.     print "[\x01b[1;32;40mRr\x01b[0;37;44m](edraw)?  -> re-display last screen.";
  529.     print "[\x01b[1;32;40mFf\x01b[0;37;44m](ile)?    -> proceed to next file.";
  530.     print "[\x01b[1;32;40mNn\x01b[0;37;44m](umbers)? -> turn line numbers on/off.";
  531.     print "[\x01b[1;32;40mTt\x01b[0;37;44m](abs)?    -> Sub. Tabs - toggle on/off, starts off, currently:" ∩ tabs;
  532.     print "                 if on, replace tabs with blank";
  533.     print "[\x01b[1;32;40mCc\x01b[0;37;44m](ontext)? -> Review Search and High Lighted Text Patterns";
  534.     print "[\x01b[1;32;40mIi\x01b[0;37;44m](nit)?    -> re-Initialize";
  535.     print "\x01b[1;32;40mi+\x01b[0;37;44m            -> Go To Line number i, if i > current line number.";
  536.     print "\x01b[1;32;40mi*l\x01b[0;37;44m           -> skip forward i Lines.";
  537.     print "\x01b[1;32;40mi*s\x01b[0;37;44m           -> skip forward i Screens.";
  538.     print "\x01b[1;32;40mi*/r/\x01b[0;37;44m         -> search for ith expression. If found begin";
  539.     print "                 display starting 'p' lines before matching line.";
  540.     print "\x01b[1;32;40mi*m\x01b[0;37;44m           -> search for next ith Match to previous";
  541.     print "                 regular expression.";
  542.     print "\x01b[1;32;40mi*p\x01b[0;37;44m           -> set number of lines prior to match to display";
  543.     print "                 defaults to 15 if i not specified.";
  544.     print "\x01b[1;32;40mi*d\x01b[0;37;44m           -> set display line length to i, 79 default";
  545.     print "\x01b[1;32;40mhi*/r/\x01b[0;37;44m        -> High-light text matching ith expression";
  546.     print "\x01b[1;32;40mri*/r/s/\x01b[0;37;44m      -> Replace r with string s";
  547.       } else {
  548.     print "MORE File Function Commands";
  549.     print "Commands: (i stands for an integer matched by {_d}.)";
  550.     print "i* means the integer is optional  (match {_d}*) - 1 defaults.";
  551.     print "i+ means the integer is mandatory (match {_d}+) - no default.";
  552.     print "[Qq](uit)?    -> exit to DOS.";
  553.     print "[Rr](edraw)?  -> re-display last screen.";
  554.     print "[Ff](ile)?    -> proceed to next file.";
  555.     print "[Nn](umbers)? -> turn line numbers on/off.";
  556.     print "[Tt](abs)?    -> Sub. Tabs - toggle on/off, starts off, currently:" ∩ tabs;
  557.     print "                 if on, replace tabs with blank";
  558.     print "[Cc](ontext)? -> Review Search and High Lighted Text Patterns";
  559.     print "[Ii](nit)?    -> re-Initialize";
  560.     print "i+            -> Go To Line number i, if i > current line number.";
  561.     print "i*l           -> skip forward i Lines.";
  562.     print "i*s           -> skip forward i Screens.";
  563.     print "i*/r/         -> search for ith expression. If found begin";
  564.     print "                 display starting 'p' lines before matching line.";
  565.     print "i*m           -> search for next ith Match to previous";
  566.     print "                 regular expression.";
  567.     print "i*p           -> set number of lines prior to match to display";
  568.     print "                 defaults to 15 if i not specified.";
  569.     print "i*d           -> set display line length to i, 79 default";
  570.     print "hi*/r/        -> High-light text matching ith expression";
  571.     print "ri*/r/s/      -> Replace r with string s";
  572.     }
  573. }
  574.  
  575. # function to clear screen and home cursor
  576. # NOTE: MUST have ANSI.SYS device driver installed to work
  577. function cls() {
  578.       # clear screen and home cursor string
  579.     local _cls_ = "\x01b[2J";
  580.  
  581.     fprintf(stderr,_cls_);
  582. }
  583.  
  584. # function to get size of filename passed
  585. function get_size(filename) {
  586.     local tmp_file = "$tmptmp$.dir";
  587.     local gdir = "dir " ∩ filename ∩ " >" ∩ tmp_file;
  588.     local ddir = "del " ∩ tmp_file;
  589.     local inline;
  590.     local fsize = 0;
  591.     local size_field = 3; # Use 2 for 4DOS, 3 for PC/MS-DOS
  592.  
  593.     system(gdir);
  594.     fgetline(tmp_file,inline);    # read and discard header lines
  595.     fgetline(tmp_file,inline);    # read and discard header lines
  596.     fgetline(tmp_file,inline);    # read and discard header lines
  597.     # comment following line for 4DOS
  598.     fgetline(tmp_file,inline);    # read and discard header lines
  599.     while ( fgetline(tmp_file,inline) > 0 ) {
  600.     print inline;
  601.       # discard if not a filename line
  602.     if ( inline !~ /^[A-Za-z]/ ) continue;
  603.       # discard if a directory name line
  604.     if ( inline ~~ /{_w}+<DIR>{_w}+/ ) continue;
  605.       # split out file information
  606.     nf = split(inline,tmparr);
  607.       # form "filename.ext"
  608.     fsize = tmparr[size_field] + 0;
  609.     break;
  610.     }
  611.       # delete temporary directory file
  612.     close(tmp_file);
  613.     system(ddir);
  614.     return fsize;
  615. }
  616.  
  617. # Function to get desired file names and print
  618. # Use DOS "dir" command to list all files to a temporary file
  619. # read temporary file picking up:
  620. # 1) path from third line
  621. # 2) filenames from remainder of lines
  622. # 3) match filenames against filepattern for desired files and print if match
  623. # Could also get file sizes, dates and times if desired
  624. #
  625. # Arguments passed:
  626. #   dir ==> path of desired files
  627. #   file_template ==> array of string or regular expression patterns
  628. #              for filenames
  629. #
  630. function getdir(dir,file_template) {
  631.     local tmp_file = "$tmptmp$.dir";
  632.     local gdir = "dir " ∩ dir ∩ "*.* > " ∩ tmp_file;
  633.     local ddir = "del " ∩ tmp_file;
  634.     local tmparr, inline, filename;
  635.     local f_indx = 1, f_list;
  636.     local i;
  637.     local size_field = 3; # Use 2 for 4DOS, 3 for PC/MS-DOS
  638.  
  639.     system(gdir);
  640.     fgetline(tmp_file,inline);    # read and discard header lines
  641.     # comment following line for 4DOS
  642.     fgetline(tmp_file,inline);    # read and discard header lines
  643.     fgetline(tmp_file,inline);    # read and discard header lines
  644.     split(inline,tmparr);    # split out to get path
  645.     drive = substr(tmparr[3],1,2);   # set disk drive
  646.     path = sustr(tmparr[3],3) ∩ '\\';   # delete drive and set path
  647. #    print drive ∩ path;     # un-comment to print path
  648.     # comment following line for 4DOS
  649.     fgetline(tmp_file,inline);    # read and discard header lines
  650.     while ( fgetline(tmp_file,inline) > 0 ) {
  651.       # discard if not a filename line
  652.     if ( inline !~ /^[A-Za-z]/ ) continue;
  653.       # discard if a directory name line
  654.     if ( inline ~~ /{_w}+<DIR>{_w}+/ ) continue;
  655.       # split out file information
  656.     nf = split(inline,tmparr);
  657.       # form "filename.ext"
  658. #      filename = tmparr[1] ∩ '.' ∩ tmparr[2];
  659.     filename = tmparr[1];
  660.     for ( i in file_template ) {
  661. #         if ( filename ~~ file_template[i] ) {
  662.         if ( strupr(filename) ~~ file_template[i] ) {
  663.         f_list[f_indx++] = filename;
  664.         # store file size as integer
  665.         if ( tmparr[size_field] ~~ /^{_d}+$/ )
  666.           file_sizea[fsize_indx++] = tmparr[size_field] + 0;
  667.         break;
  668.         }
  669.     }
  670.     }
  671.       # delete temporary directory file
  672.     close(tmp_file);
  673.     system(ddir);
  674.     return f_list;
  675. }
  676.  
  677. #function to display command line help
  678. function cmd_help() {
  679.     cls;
  680.     print "Usage:";
  681.     if ( ansi ) {
  682.     print "\x01b[1;32;40mQTAwk -fmore.exp -- [-ppath] [+/r.e.[/]] file1 file2 ...\x01b[0;37;44m";
  683.     print "Options:";
  684.     print " ppath - specifiy path to find files";
  685.     print " +/r.e./ - specify regular expression for starting search";
  686.     print "Commands:";
  687.     print "i below stands for an integer matched by {_d}.";
  688.     print "i* means the integer is optional  (match {_d}*) - 1 defaults.";
  689.     print "i+ means the integer is mandatory (match {_d}+) - no default.";
  690.     print "[\x01b[1;32;40mQq\x01b[0;37;44m](uit)?    -> exit to DOS.";
  691.     print "[\x01b[1;32;40mRr\x01b[0;37;44m](edraw)?  -> re-display last screen.";
  692.     print "[\x01b[1;32;40mFf\x01b[0;37;44m](ile)?    -> proceed to next file.";
  693.     print "[\x01b[1;32;40mNn\x01b[0;37;44m](umbers)? -> turn line numbers on/off.";
  694.     print "[\x01b[1;32;40mTt\x01b[0;37;44m](abs)?    -> Sub. Tabs - toggle on/off, starts off, currently:" ∩ tabs;
  695.     print "                 if on, replace tabs with blank";
  696.     print "[\x01b[1;32;40mCc\x01b[0;37;44m](ontext)? -> Review Search and High Lighted Text Patterns";
  697.     print "[\x01b[1;32;40mIi\x01b[0;37;44m](nit)?    -> re-Initialize";
  698.     print "\x01b[1;32;40mi+\x01b[0;37;44m            -> Go To Line number i, if i > current line number.";
  699.     print "\x01b[1;32;40mi*l\x01b[0;37;44m           -> skip forward i Lines.";
  700.     print "\x01b[1;32;40mi*s\x01b[0;37;44m           -> skip forward i Screens.";
  701.     print "\x01b[1;32;40mi*/r/\x01b[0;37;44m         -> search for ith expression. If found begin";
  702.     print "                 display starting 'p' lines before matching line.";
  703.     print "\x01b[1;32;40mi*m\x01b[0;37;44m           -> search for next ith Match to previous";
  704.     print "                 regular expression.";
  705.     print "\x01b[1;32;40mi*p\x01b[0;37;44m           -> set number of lines prior to match to display";
  706.     print "                 defaults to 15 if i not specified.";
  707.     print "\x01b[1;32;40mi*d\x01b[0;37;44m           -> set display line length to i, 79 default";
  708.     print "\x01b[1;32;40mhi*/r/\x01b[0;37;44m        -> High-light text matching ith expression";
  709.     print "\x01b[1;32;40mri*/r/s/\x01b[0;37;44m      -> Replace r with string s";
  710.       } else {
  711.     print "QTAwk -fmore.exp -- [-ppath] [+/r.e.[/]] file1 file2 ...";
  712.     print "Options:";
  713.     print " ppath - specifiy path to find files";
  714.     print " +/r.e./ - specify regular expression for starting search";
  715.     print "Commands:";
  716.     print "i below stands for an integer matched by {_d}.";
  717.     print "i* means the integer is optional  (match {_d}*) - 1 defaults.";
  718.     print "i+ means the integer is mandatory (match {_d}+) - no default.";
  719.     print "[Qq](uit)?    -> exit to DOS.";
  720.     print "[Rr](edraw)?  -> re-display last screen.";
  721.     print "[Ff](ile)?    -> proceed to next file.";
  722.     print "[Nn](umbers)? -> turn line numbers on/off.";
  723.     print "[Tt](abs)?    -> Sub. Tabs - toggle on/off, starts off, currently:" ∩ tabs;
  724.     print "                 if on, replace tabs with blank";
  725.     print "[Cc](ontext)? -> Review Search and High Lighted Text Patterns";
  726.     print "[Ii](nit)?    -> re-Initialize";
  727.     print "i+            -> Go To Line number i, if i > current line number.";
  728.     print "i*l           -> skip forward i Lines.";
  729.     print "i*s           -> skip forward i Screens.";
  730.     print "i*/r/         -> search for ith expression. If found begin";
  731.     print "                 display starting 'p' lines before matching line.";
  732.     print "i*m           -> search for next ith Match to previous";
  733.     print "                 regular expression.";
  734.     print "i*p           -> set number of lines prior to match to display";
  735.     print "                 defaults to 15 if i not specified.";
  736.     print "i*d           -> set display line length to i, 79 default";
  737.     print "hi*/r/        -> High-light text matching ith expression";
  738.     print "ri*/r/s/      -> Replace r with string s";
  739.    }
  740. }
  741. # function to set patterns for highlighting in manuals
  742. function manual_high() {
  743.     # set patterns to delete and replace printer control codes
  744.     # emphasized/underline codes
  745.     Replace_pat[10][0] = /\x01b([EF]|-[\x001\x080])/;
  746.     Replace_pat[10][1] = "";
  747.  
  748.     # set patterns to highlight text surrounded by printer emphasized code
  749.     High_pat[10] = /\x01bE.+\x01bF/;
  750.     High_Text[10] = Red_on_Blackh;
  751.  
  752.     # set expressions for highlighting desired expressions
  753.     High_pat[11] = /[Rr]egular|[Ee]xpressions?/; # highlight "regular expression"
  754.     High_Text[11] = Green_on_Blackh;
  755.     High_pat[12] = /Q[TS]grep|QTAwk/;
  756.     High_Text[12] = Yellow_on_Blackh;
  757.     High_pat[13] = /[Kk]eyword/;
  758.     High_Text[13] = Blue_on_Blackh;
  759.     High_pat[14] = /BEGIN|END|INITIAL(IZE)?|FINAL|NOMATCH|GROUP/;
  760.     High_Text[14] = Green_on_Blackh;
  761.     High_pat[15] = /[Pp]attern|[Aa]ction/;
  762.     High_Text[15] = Green_on_Blackh;
  763. }
  764.