#! /usr/bin/gawk -E # nexbro -- a gawk-based Nex browser # ex: $ nexbro nightfall.city:1900 /nex/info/ BEGIN { if (ARGC == 1 || ARGV[1] ~ /^-.*/) usage() # set HOST & PORT: HOST = ARGV[1] PORT = 1900 if ( match (HOST,":[0-9]+$") > 0 ) { HOST = substr(ARGV[1],1,RSTART-1) PORT = substr(ARGV[1],RSTART+1) } # set # rows of TERM: #N_ROWS = get_rows() - 3 N_ROWS = get_rows() - 2 # create global links array: link = 1 links[link] = (ARGV[2] ? ARGV[2] : "/") # set initial CURR link: CURR = links[link] # create global history array: hist = 1 history[hist] = CURR # main loop: while(1) { fetchlink(link) #if (ERRNO !~ /^$/) exit 0 link = getnext() if (link ~ /^q|Q$/) exit 0 history[hist] = CURR } } # ::: supporting functions ::: # # get # rows of TERM from tput(1): function get_rows(CMD) { CMD = "tput lines" CMD |getline close(CMD) return $0 - 2 } # show user input options: function showopts() { print " [N] '#'(link), 'b'(ack), 'r'(efresh), 'h'(ome), or 'q'(uit)" } # get next action from user input: function getnext( L, i) { # :v:testing:v: print link list at end.. #if ( (length(links)) ) { # print "\n::: Document Links :::\n" # for(i in links) # print "["i"]", links[i] #} # :^:testing:^: # printf "\n [N]> " getline L < "/dev/stdin" while (L ~ /^$/) { showopts() printf " [N]> " getline L < "/dev/stdin" } return L } # set CURR link, incr history, & clear old links: function setcurr(L) { if (L in links) { CURR = links[L] hist++ } else if (L ~ /^b$/) { CURR = history[--hist] } else if (L ~ /^r$/) { CURR = history[hist] } else CURR = "/" delete links } # workhorse function: function fetchlink(L, N, BASE, NL) { # clear screen via ASCII escape: print "\033[H\033[2J" # set CURR link: setcurr(L) # gawk network socket: SOCKET = "/inet/tcp/0/" HOST "/" PORT # attempt to use system pty (GAWK Manual, Chap. 12.4): PROCINFO[SOCKET, "pty"] = 1 # try to make IO non-fatal (GAWK Manual, Chap. 12.4): PROCINFO[SOCKET, "NONFATAL"] = 1 # send doc request: print CURR |& SOCKET # retrieve doc, process & pop links array: NL = 1 while (SOCKET |& getline > 0) { sub ("\r$", "") # delete the dang carrage return.. if ($0 ~ /^=> / && CURR ~ /[/]$/) { BASE = $2 $1 = $2 = "" if (BASE ~ /^[^/]/) links[++N] = CURR "/" BASE # relative path else links[++N] = BASE # absolute path gsub(/[/]+/,"/",links[N]) printf "[%02d] => %s %s\n", N, BASE, $0 } else print $0 # ::PAGER:: pause after each N_ROWS: if (NL++ % N_ROWS == 0) { #printf "\n %s", "press ENTER to continue, 'q' to quit.. " #getline < "/dev/stdin" # v=== new code ===v # hide cursor.. printf "\033[?25l" while (getline < "/dev/stdin" == 1 && $0 !~ /^(q|Q|())$/) { if ($0 ~ /.+/) { # bold text.. printf "\033[1m" printf "\t%s", "press ENTER to continue, 'q' to quit.. " # reset text.. printf "\033[0m" } } if ($0 ~ /^q|Q$/) break } # show cursor.. printf "\033[?25h" # ^=== new code ===^ } close(SOCKET) } # print usage & exit: function usage() { print "\n desc: a nex (smolnet) client written in gawk." print "\n usage: nexbro.awk HOST[:PORT] [PATH] ; defaults: PORT=1900, PATH='/'" print "\n ex: $ nexbro.awk nightfall.city /nex/info/ \n" exit 0 }