# -*- version-control: t; -*-
# Time-stamp: <CJ2K: [agvs.awk] 2016-08-12 11:58:28 edt>
# agvs.awk is licensed under the terms of the LGPLv2.1
# http://opensource.org/licenses/LGPL-2.1
# Copyright (c) 2011,2012,2013,2014,2015,2016,
# Jacques Champagne (cj2k*).
#
# All rights reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA
#
# AWK global variables space.
############################################################
# [todo: 20xx-xx-xx ] Alpha 0.2.2 add configs in AGVS array
# [UpDate: 2016-08-12 ] Version 0.2.1 public release
# [UpDate: 2016-08-09 ] Alpha 0.2.1 remove dependency
# [UpDate: 2016-08-07 ] Alpha 0.2.0 usable as agvs.awk
# [UpDate: 2011-07-17 ] Version 0.02 usable as ENVSpace.awk
# [UpDate: 2011-07-17 ] Version 0.01 usable as BIV.awk
# [UpDate: 2011-06-18 ] Beta 0.01 stand alone as library
# [Orig: 2011-04-27 ] Alpha 0.01 initial use in many scripts
# todo: add gnu awk, mawk, nawk and posix awk specifics global variables
# todo: add AGVS["stamp"] = (1|2|4|6) for default operation with stamp=agvs()
# todo: add AGVS["op"] = (1|2|4|6) for default operation with agvs(stamp)
# todo: add OFMT ARGC ARGV
# todo: create help file with examples
# maybe: use SYMTAB ??? not in mawk
# todo: add escape for regex
############################################################
#BEGIN{# todo: add auto-configs in AGVS array
# AGVS["AWKPROGRAM"]=ARGV[0];
# # todo: AGVS["AWKPROGRAM"] select the appropriate space
# AGVS[ "AWK"]="|SUBSEP|FS|RS|ORS|OFS|RLENGTH|RSTART|FILENAME|FNR|NR|NF|$0"
# AGVS["NAWK"]=AGVS[ "AWK"]#"|"
# AGVS["MAWK"]=AGVS[ "AWK"]"|"
# AGVS["GAWK"]=AGVS[ "AWK"]"|"
#}
############################################################
# agvs:
# Allow opperation with a differents global variables space.
# Space is defined as a colection of global variables.
# The space is saved in AGVS array with a stamp as reference for the collection.
# When saving a space, the function return a stamp for later use in program.
# usage:
# stamp=agvs() push agv, return: new stamp
# agvs(stamp) pop agv, return: 0 or 6 for restored and deleted
# agvs(stamp, "+") save, return: stamp
# agvs(stamp, "?") test, return: 0 or 1 for saved
# agvs(stamp, "%") restore, return: 0 or 2 for restored
# agvs(stamp, "-") delete, return: 0 or 4 for deleted
# agvs(stamp, "!") pop, return: 0 or 6 for restored and deleted
function agvs(stamp,op,sel, d,i,r,s,t,Z){
# AGVS["AWKPROGRAM"]=ARGV[0]
s= sprintf("%06X", rand()*10000000)\
sprintf("%06X", rand()*10000000)
s= !stamp? s: stamp;
# stamp: string that group global variables in AGVS array
# default to hex random integer as string
op= !op? (!stamp? "+": "!"): tolower(op); stamp=s;
# op: operations on a spcifics gvs;
# default: if stamp=="" push else pop
# operations alias:
# /in|test|saved|[?]/ test if a space is saved in AGVS array
# /save|add|push|[+]/ add a space to AGVS array
# /load|restore|[%]/ restore a space from AGVS array
# /del|delete|[-]/ delete a space from AGVS array
# /pop|[!]/ restore and delete a space from AGVS array
# sel: argument to select spcifics global variables
# first char is the splitter; "|SUBSEP|FS|RS| ... |NF|$0"
# default to;
i="|SUBSEP|FS|RS|ORS|OFS|RLENGTH|RSTART|FILENAME|FNR|NR|NF|$0"
sel= !sel? (stamp in AGVS? AGVS[stamp]: i): sel;
split(sel,t,"["substr(sel,1,1)"]");# todo: add escape for regex
for(i in t) if(t[i]){ t[t[i]]; delete t[i] }
if(op ~ /in|test|saved|[?]/)return stamp in AGVS; # test saved
if(op ~ /save|add|push|[+]/){# Save awk global variables
AGVS[stamp]=sel; AGVS[ ++AGVS["AGVS"] ]=stamp;
if("SUBSEP" in t)AGVS[stamp"|SUBSEP"] =SUBSEP # stream control
if("RS" in t)AGVS[stamp"|RS"] =RS
if("FS" in t)AGVS[stamp"|FS"] =FS
if("OFS" in t)AGVS[stamp"|OFS"] =OFS
if("ORS" in t)AGVS[stamp"|ORS"] =ORS
if("FILENAME" in t)AGVS[stamp"|FILENAME"] =FILENAME # stream info
if("FNR" in t)AGVS[stamp"|FNR"] =FNR
if("NR" in t)AGVS[stamp"|NR"] =NR
if("NF" in t)AGVS[stamp"|NF"] =NF
if("$0" in t)AGVS[stamp"|$0"] =$0
if("RLENGTH" in t)AGVS[stamp"|RLENGTH"] =RLENGTH # match function
if("RSTART" in t)AGVS[stamp"|RSTART"] =RSTART
return stamp}# /save|push|[+]/
if(op ~ /load|restore|pop|[!%]/ && (r=stamp in AGVS)){# Load or pop
if("SUBSEP" in t)SUBSEP= AGVS[stamp"|SUBSEP"] # stream control
if("FS" in t)FS= AGVS[stamp"|FS"]
if("RS" in t)RS= AGVS[stamp"|RS"]
if("OFS" in t)OFS= AGVS[stamp"|OFS"]
if("ORS" in t)ORS= AGVS[stamp"|ORS"]
if("FILENAME" in t)FILENAME= AGVS[stamp"|FILENAME"] # stream info
if("FNR" in t)FNR= AGVS[stamp"|FNR"]
if("NR" in t)NR= AGVS[stamp"|NR"]
if("NF" in t)NF= AGVS[stamp"|NF"]
if("$0" in t)$0= AGVS[stamp"|$0"]
if("RLENGTH" in t)RLENGTH= AGVS[stamp"|RLENGTH"] # match function
if("RSTART" in t)RSTART= AGVS[stamp"|RSTART"]
r=r? 2: r;# 2
}# /load|restore|pop|[!%]/
if(op ~ /del|delete|pop|[!-]/ && (d=stamp in AGVS)){# delete or pop
for(i in t) delete AGVS[stamp"|"i];
delete AGVS[stamp]; delete AGVS[ AGVS["AGVS"]-- ];
r=d? r+4: r;# 4 or 6
}# /del|delete|pop|[!-]/
return r}#