[CrackMonkey] uuencode in awk!
Joey Hess
joey at kitenet.net
Thu Jul 27 03:12:33 PDT 2000
Nick Moffitt wrote:
> It has uudecode in awk!
Incomplete debconf inplementation in awk (and it'll be finished over my
dead body (if you don't know what debconf is, go away)):
#!/usr/bin/mawk -f
#
# Nanoconf, a tiny debconf-compatible configuration system.
#
# Copyright (C) 2000 Massimo Dal Zotto <dz at cs.unitn.it>
BEGIN {
NANOCONF_VERSION = "0.1"
PROTOCOL_VERSION = "2.0"
STDERR = "/dev/stderr"
MBOX = or(env("MAILBOX"), env("HOME")"/nanoconf-messages")
TEMPFILE = or(env("TMP"),"/tmp") "/nanoconf" getpid() rand()
TTY = or(env("NANOCONF_TTY"), "/dev/tty")
debug(1,"# nanoconf version "NANOCONF_VERSION)
make_array(flag_keywords, \
"flag_isdefault")
make_array(type_keywords, \
"string boolean select multiselect note text password")
make_array(priority_keywords, \
"low medium high critical")
make_array(template_keywords, \
"choices default description template type " \
"extended_choices extended_default extended_description " \
"extended_template extended_type")
make_array(question_keywords, \
"choices default description template type " \
"extended_choices extended_default extended_description " \
"extended_template extended_type " \
"flag_isdefault name owners value variables")
nanoconf["templates_db"] = or(templates_db, env("NANOCONF_TEMPLATES"), \
"/var/lib/nanoconf/templates.db")
nanoconf["config_db"] = or(config_db, env("NANOCONF_DB"), \
"/var/lib/nanoconf/debconf.db")
nanoconf["title"] = or(title, env("NANOCONF_TITLE"),
"Package Configuration")
nanoconf["backtitle"] = or(backtitle, env("NANOCONF_BACKTITLE"))
nanoconf["package"] = or(package, env("NANOCONF_PACKAGE"))
nanoconf["auto_go"] = or(auto_go, env("NANOCONF_AUTO_GO")) # debug
# Load the database
db_load(TDB, nanoconf["templates_db"])
db_load(QDB, nanoconf["config_db"])
nanoconf["priority"] = tolower(or(priority, env("NANOCONF_PRIORITY"), \
get_value("debconf/priority"), "normal"))
nanoconf["frontend"] = tolower(or(frontend, env("NANOCONF_FRONTEND"), \
get_value("debconf/frontend"), "dialog"))
nanoconf["showold"] = or(showold, env("NANOCONF_SHOWOLD"), \
get_value("debconf/showold"), "false")
nanoconf["lang"] = or(lang, env("LANG"),
get_value("debconf/lang"))
if (DEBUG) { parray(nanoconf,"nanoconf","/dev/stderr") } # debug
}
END {
run("rm -f "quote(TEMPFILE))
debug(1,"# nanoconf ended")
}
{ debug(2,"%s %s",NR,$0) }
# Nanoconf command extensions
(tolower($1) == "list") { cmd_list($2); next }
(tolower($1) == "load") { cmd_load($2,$3); next }
(tolower($1) == "save") { cmd_save($2,$3); next }
(tolower($1) == "setvar") { cmd_set($2,$3,0); next }
(tolower($1) == "package") { cmd_package($1); next }
(tolower($1) == "quit") { cmd_quit(); next }
(tolower($1) == "q") { exit }
($1 == "") { next }
# Debconf standard commands
($1 == "BEGINBLOCK") { cmd_beginblock(); next }
($1 == "CAPB") { cmd_capb(); next }
($1 == "CLEAR") { cmd_clear(); next }
($1 == "ENDBLOCK") { cmd_endblock(); next }
($1 == "FGET") { cmd_fget($2,$3); next }
($1 == "FSET") { cmd_fset($2,$3,$4); next }
($1 == "GET") { cmd_get($2); next }
($1 == "GO") { cmd_go(); next }
($1 == "INPUT") { cmd_input($2,$3); next }
($1 == "METAGET") { cmd_metaget($2,$3); next }
($1 == "PREVIOUS_MODULE") { cmd_previous_module(); next }
($1 == "PURGE") { cmd_purge(); next }
($1 == "REGISTER") { cmd_register($2,$3); next }
($1 == "RESET") { cmd_reset($2); next }
($1 == "SET") { cmd_set($2,$3,$4); next }
($1 == "STOP") { cmd_stop(); next }
($1 == "SUBST") { cmd_subst($2,$3,$4); next }
($1 == "TITLE") { cmd_title(); next }
($1 == "UNREGISTER") { cmd_unregister($2); next }
($1 == "VERSION") { cmd_version($2); next }
# Debconf command aliases
($1 == "NOTE") { cmd_input($2,$3); next }
($1 == "TEXT") { cmd_input($2,$3); next }
# Unknown input
{ cmd_unknown() }
function cmd_beginblock() {
debug(1,"# cmd_beginblock")
print 0
}
# Capabilities are in $2-$N
function cmd_capb(x) {
$1 = ""; sub("^ \t+","")
debug(1,"# cmd_capb %s",$0)
print 0, "multiselect backup"
}
function cmd_clear() {
debug(1,"# cmd_clear")
delete_all_questions()
print 0
}
function cmd_endblock() {
debug(1,"# cmd_endblock")
print 0
}
function cmd_fget(var,flag) {
debug(1,"# cmd_fget %s %s",var,flag)
if (undefined(var)) return
print 0, db_get_field(QDB,var,"flag_"flag)
}
function cmd_fset(var,flag,val) {
debug(1,"# cmd_fset %s %s %s",var,flag,val)
if (undefined(var)) return
print 0, db_set_field(QDB,var,"flag_"flag,val)
}
function cmd_get(var, val,isdefault) {
debug(1,"# cmd_get %s",var)
if (undefined(var)) return
print 0, get_value(var)
}
function cmd_go() {
debug(1,"# cmd_go")
if (ask_all_questions()) {
print 0
} else {
# Backup request from user
print 30
}
delete_all_questions()
}
function cmd_input(priority,var) {
debug(1,"# cmd_input %s %s",priority,var)
if (undefined(var)) return
if (!add_question(var,priority)) {
# Old question or not allowed by current priority
print 30
return
}
if (nanoconf["auto_go"]) { return cmd_go() } # debug
print 0
}
function cmd_list(expr, nkeys,_K,_T,d) {
debug(1,"# cmd_list %s",expr)
gsub("\\*",".*",expr)
split(QDB[""],_T)
for (i in _T) {
if (expr && (!match(_T[i],"^"expr))) continue
_K[++nkeys] = _T[i]
}
delete _T
isort(_K, nkeys)
for (i=1; i<=nkeys; i++) {
d=(is_default(_K[i]) ? "default" : "")
print _K[i]"='"get_value(_K[i])"' [" d"]" > STDERR
}
delete _K
print 0
}
function cmd_load(which,file) {
debug(1,"# cmd_load %s %s",which,file)
if (match("templates","^"which)) {
print 30*(!db_load(TDB, file))
return
}
if ((match("questions","^"which)) || (match("db","^"which))) {
print 30*(!db_load(QDB, file))
return
}
if (match("file","^"which)) {
print 30*(!db_load_template(file))
return
}
print 20, "syntax error"
}
function cmd_metaget(var,field, val) {
debug(1,"# cmd_metaget %s %s",var,field)
if (undefined(var)) return
val = db_get_field(QDB,var,field)
if (db_undef(QDB)) {
val = db_get_field(TDB,var,field)
}
print 0, val
}
function cmd_package(p) {
debug(1,"# cmd_package %s",p)
if (p) {
nanoconf["package"] = p
}
print 0, nanoconf["package"]
}
function cmd_previous_module() {
debug(1,"# cmd_previous_module")
print 30, "not supported"
}
# XXX - todo
function cmd_purge() {
debug(1,"# cmd_purge")
# delete all vars and templates for current package
print 0
}
# Exit without saving
function cmd_quit() {
debug(1,"# cmd_quit")
print 0, "quit"
exit 0
}
# XXX - todo
function cmd_register(template,var) {
debug(1,"# cmd_register %s %s",template,var)
print 0
}
function cmd_reset(var) {
debug(1,"# cmd_reset %s",var)
if (undefined(var)) return
set_value(var, get_default(var), 1)
print 0
}
function cmd_save(which,file) {
debug(1,"# cmd_save %s %s",which,file)
if (!which) {
print 30*(!db_save(TDB, nanoconf["templates_db"]) || \
(!db_save(QDB, nanoconf["config_db"])))
return
}
if (match("templates","^"which)) {
print 30*(!db_save(TDB, file))
return
}
if ((match("questions","^"which)) || (match("db","^"which))) {
print 30*(!db_save(QDB, file))
return
}
print 20, "syntax error"
}
# Optional arg isdefault is a nanoconf extension
function cmd_set(var,val,isdefault) {
debug(1,"# cmd_set %s %s %s",var,val,isdefault)
if (undefined(var)) return
set_value(var,val,isdefault)
print 0
}
# cmd_stop exits without printing anything
function cmd_stop() {
debug(1,"# cmd_stop")
db_save(TDB, nanoconf["templates_db"])
db_save(QDB, nanoconf["config_db"])
exit 0
}
# XXX - todo
function cmd_subst(var,key,val) {
debug(1,"# cmd_subst %s %s %s",var,key,val)
print 30, "not supported"
}
# Title string is in $2-$N
function cmd_title() {
$1 = ""; sub("^ \t+","")
debug(1,"# cmd_title %s",$0)
nanoconf["title"] = $0
print 0
}
function cmd_unknown(var) {
debug(1,"# cmd_unknown %s",$1)
print 20, "Unsupported command "$1" received from confmodule."
}
# XXX - todo
function cmd_unregister(var) {
debug(1,"# cmd_unregister %s",var)
print 0
}
function cmd_version(vers, p,v) {
debug(1,"# cmd_version %s",vers)
v = vers; sub("\..*","",v)
p = PROTOCOL_VERSION; sub("\..*","",p)
if (v < p) {
print 30, "Version too low (" vers ")"
return
}
if (v > p) {
print 30, "Version too high (" vers ")"
return
}
print 0, PROTOCOL_VERSION
}
# end of file
# Misc utilities
#
# max(x,y)
# min(x,y)
# or(...)
# env(x)
# getpid()
# date(fmt)
# run(cmd)
# readfile(file)
# readpipe(cmd)
# test_x(file)
# escape(text,chars)
# quote(text,q)
# wrap(text,width)
# debug(level,fmt,...)
# make_array(table,flags)
# parray(array,aname,file,expr)
# isort(A,n)
function max(x,y) {
return ((x>y)?x:y)
}
function min(x,y) {
return ((x<y)?x:y)
}
function or(a,b,c,d,e) {
if (a) return a
if (b) return b
if (c) return c
if (d) return d
if (e) return e
}
function env(x) {
return ENVIRON[x]
}
function getpid( cmd,x) {
cmd = "echo $PPID"
cmd | getline x
close(cmd)
return x
}
function date(fmt, cmd,x) {
if (fmt) fmt = quote(fmt)
cmd = "date "fmt
cmd | getline x
close(cmd)
return x
}
function run(cmd, rc) {
if (DEBUG) { print "# run "cmd > STDERR } # debug printf limit is 1020
rc = system(cmd)
debug(2,"# rc="rc)
return rc
}
function readfile(file, result) {
debug(2, "# readfile %s", file)
while ((getline line < file) > 0) {
result = result"\n"line
}
close(file)
sub("\n","",result)
return result
}
function readpipe(cmd, result) {
debug(2, "# readpipe %s", cmd)
while ((cmd | getline line) > 0) {
result = result"\n"line
}
close(cmd)
sub("\n","",result)
return result
}
function test_x(file) {
return !system("test -x " escape(file))
}
function escape(text,chars, i,c) {
gsub("\\\\","\\\\\\\\",text)
chars = or(chars,"'")
for (i=1; i<=length(chars); i++) {
c = substr(chars,i,1); gsub("\\"c,"\\\\"c,text)
}
return text
}
function quote(text,q) {
q = or(q,"\"")
return q escape(text,q"`$") q
}
function wrap(text,width, _wrap,n,i,j,k,line,s,c) {
n = split(text,_wrap,"\n"); text = ""; width=or(width,72)
for (i=1; i<=n; i++) {
line = _wrap[i]
while ((l=length(line)+7*gsub("\t","\t",line)) > width) {
k = width
for (j=1; j<=(width+1); j++) {
c = substr(line,j,1)
if ((c==" ")||(c=="\t")) { k = j }
}
text = text"\n"substr(line,1,k)
line = substr(line,k+1); sub("^[ \t]+","",line)
}
text = text"\n"line
}
delete _wrap
sub("\n","",text)
return text
}
# Debug is required also in non-debug mode
function debug(level,fmt,a,b,c,d,e,f,g,h,i,j,k,l,m,n) {
if (level+0 == 0) {
# Unconditional debug, level is the fmt string
printf (level"\n",fmt,a,b,c,d,e,f,g,h,i,j,k,l,m,n) > STDERR
} else if (level+0 <= DEBUG) {
printf (fmt"\n",a,b,c,d,e,f,g,h,i,j,k,l,m,n) > STDERR
}
fflush(STDERR)
}
function make_array(table,flags, i,n,_array) {
n = split(flags,_array)
for (i=1; i<=n; i++) {
table[_array[i]] = _array[i]
}
delete _array
}
function parray(array,aname,file,expr, _parray,nkeys) {
if (!aname) { aname = "array" }
if (!file) { file = "/dev/stdout" }
for (key in array) {
if (expr && (!match(key,expr))) continue
_parray[++nkeys] = key
}
isort(_parray, nkeys)
print aname "=" nkeys >> file
for (i=1; i<=nkeys; i++) {
key = _parray[i]
print aname"["key"]='"array[key]"'" >> file
}
delete _parray
print "" >> file
}
function isort(A,n, i,j,t) {
for(i=2; i<=n; i++) {
t=A[j=i]
while (A[j-1]>t) { j--; A[j+1]=A[j] }
A[j]=t
}
}
# end of file
# Function for accessing debconf variables
#
# undefined(var)
# is_default(var)
# get_value(var)
# set_value(var,val,isdefault)
# get_field(var,field)
# set_field(var,field,val)
# get_type(var)
# get_default(var)
# get_prompt(var)
# get_text(var)
# get_l10n_field(var,field,lang)
# Prints an error message if a variable is not defined
function undefined(var) {
if (!db_exists(QDB,var)) {
print 10, var, "doesn't exist"
return 1
}
return 0
}
function is_default(var) {
if (!db_exists(QDB,var)) {
return 1
}
return (db_get_field(QDB,var,"flag_isdefault") == "true")
}
# Returns var value or template default value
function get_value(var, val) {
# if (!db_exists(QDB,var)) {
# return
# }
val = db_get_value(QDB,var)
if (db_undef(QDB)) {
val = db_get_field(TDB,var,"default")
}
return val
}
function set_value(var,val,isdefault) {
if (!db_exists(QDB,var)) {
return
}
db_set_value(QDB,var,val,isdefault)
return val
}
# Returns a field from questions or templates db
function get_field(var,field, val) {
# if (!db_exists(QDB,var)) {
# return
# }
val = db_get_field(QDB,var,field)
if (db_undef(QDB)) {
val = db_get_field(TDB,var,field)
}
return val
}
function set_field(var,field,val) {
if (!db_exists(QDB,var)) {
return
}
if ((field in flag_keywords) || (field in question_keywords)) {
debug(1,"# set_field QDB %s %s = %s",var,field,val)
val = db_set_field(QDB,var,field,val)
} else {
debug(1,"# set_field TDB %s %s = %s",var,field,val)
val = db_set_field(TDB,var,field,val)
}
return val
}
function get_type(var) {
# if (!db_exists(QDB,var)) {
# return
# }
return db_get_field(TDB,var,"type")
}
function get_default(var) {
# if (!db_exists(QDB,var)) {
# return
# }
return db_get_field(TDB,var,"default")
}
function get_prompt(var, prompt) {
prompt = get_l10n_field(var, "description", nanoconf["lang"])
return or(prompt, "Enter value of "var)
}
function get_text(var) {
return get_l10n_field(var, "extended_description", nanoconf["lang"])
}
# Get a localized template field. Try langs in this order: ll_LL, ll, ""
function get_l10n_field(var,field,lang, ret) {
if (lang) {
ret = db_get_field(TDB, var, field"-"lang)
if (!ret && sub("_..$","",lang)) {
ret = db_get_field(TDB, var, field"-"lang)
}
}
if (!ret) {
ret = db_get_field(TDB, var, field)
}
return ret
}
# end of file
# Nanoconf database
#
# db_load(db,file)
# db_load_aux(db,file,name,indent)
# db_save(db,file)
# db_save_aux(db,file,name,last,indent)
# db_load_template(file)
# db_add(db,keywords,name,this)
# db_delete(db,keywords,name,this)
# db_set_field(db,name,key,val,type)
# db_get_field(db,name,key)
# db_get_value(db,name,default)
# db_set_value(db,name,val,isdefault)
# db_exists(db,name)
# db_undef(db)
#
# database internal format:
#
# db[""] <list of names>
# db[:name] perl hash name
# db[name:type] number, list, ref, text (default)
# db[name:class] <classname>
# db[name] <value> if type != list
# db[name] <list of subnames> if type == list
# db[name=>subname] subfield notation
# Load a debconf database
function db_load(db,file, rc) {
debug(1,"# db_load %s",file)
if (file == "") {
return 0
}
if ((getline < file) <= 0) {
print "unable to open db: "file > STDERR
return 0
}
if (!match($0,"%[a-z]+ \= \(")) {
print "invalid db format: "$0 > STDERR
return 0
}
db[":name"] = $1
$2="=>"; $3="{"
rc = db_load_aux(db,file)
debug(2,"# db_load rc=%s",rc)
close(file)
if (DEBUG >= 5) {
parray(db,"db",STDERR)
}
return rc
}
function db_load_aux(db,file,name,indent, subname,subvars,class,val) {
debug(3,"# db_load_aux name=%s indent='%s '",name,indent)
debug(6,"%d>%s",length(indent)/2,$0)
if ($2 != "=>") {
print "invalid db format: "$0 > STDERR
return 0
}
sub("^.*\ => ","")
if (match($1,"^'")) {
# Text value
# db[name":type"] = "string" assumed by default
debug(6,"# text: %s", $0)
val = $0
while (!match(val, "[^\\\]',?$")) {
if ((getline < file) <= 0) {
print "eof on string input: "$0 > STDERR
return 0
}
debug(7,"+>%s", $0)
val = val"\n"$0
}
sub("^'","",val); sub("',?$","",val)
gsub("\\\'","'",val); gsub("\\\\\\\\","\\\\",val);
db[name] = val
debug(6,"= db["name"]='%s'", db[name])
return 1
}
sub(",$","")
if (match($1,"^[0-9]+$")) {
# Numeric value
debug(6,"# number: %s", $0)
db[name":type"] = "number"
db[name] = $1
debug(6,"= db["name"]='%s'", db[name])
return 1
}
if (match($1,"^\\$.*{'.*'}$")) {
# Subst value
debug(6,"# subst %s", $0)
db[name":type"] = "subst"
db[name] = $1
debug(6,"= db["name"]='%s'", db[name])
return 1
}
if ($1 == "{}") {
# Empty list
debug(6,"# empty list: %s", $0)
db[name":type"] = "list"
db[name] = ""
debug(6,"= db["name"]='%s'", db[name])
return 1
}
if ($1 == "{") {
# Non-empty list
debug(6,"# list: %s", $0)
db[name":type"] = "list"
while ((getline < file) > 0) {
debug(6,">>%s", $0)
if (match($0,"^"indent"}")) {
debug(6,"# end list: %s", $0)
break
}
if (match($0,"^"indent" '[a-z][a-z0-9_/.-]+' \=> ")) {
sub("^"indent" '",""); sub("' => "," => ")
class = sub(" => bless\( "," => ")
debug(7,"++%s", $0)
if (name == "") {
subname = $1
} else {
subname = name"=>"$1
}
subvars = subvars" "subname
if (!db_load_aux(db,file,subname,indent" ")) {
return 0
}
if (class) {
class = $2; gsub("'","",class)
debug(6,"# class: %s", class)
db[subname":class"] = class
debug(6,"= db["subname":class]='%s'", db[subname":class"])
}
}
}
sub("^ ","",subvars)
db[name] = subvars
return 1
}
print "unknown input: "$0 > STDERR
return 0
}
# Save a database in debconf format
function db_save(db,file, i,keys,nkeys) {
debug(1,"# db_save %s", file)
if (file == "") {
return 0
}
if (!db[":name"]) {
printf "invalid db" > STDERR
return 0
}
print db[":name"]" \= \(" > file
nkeys = split(db[""],keys)
for (i=1; i<=nkeys; i++) {
if (!db_save_aux(db,file,keys[i],(i>=nkeys))) {
close(file)
return 0
}
}
print ");" > file
print "" > file
print "1;" > file
close(file);
return 1
}
function db_save_aux(db,file,name,last,indent, i,val,shortname,class,type) {
debug(3,"# db_save_aux name=%s last=%s indent='%s '",name,last,indent)
shortname = name; gsub(".*=>","",shortname)
last = (last ? "" : ",")
val = db[name]
if (name":class" in db) {
class = db[name":class"]
}
if (name":type" in db) {
type = db[name":type"]
}
printf("%s '%s' => ",indent,shortname) > file
if (class) {
printf("bless\( ") > file
}
if ((type == "string") || (type == "")) {
printf("%s", quote(val,"'")) > file
}
if (type == "number") {
printf("%s", val) > file
}
if (type == "subst") {
printf("%s", val) > file
}
if ((type == "list") && (!val)) {
printf("{}") > file
}
if ((type == "list") && (val)) {
print "{" > file
$0 = db[name]
for (i=1; i<=NF; i++) {
if (!db_save_aux(db,file,$i,(i>=NF), indent" ")) {
return 0
}
}
printf("%s \}", indent) > file
}
if (class) {
printf(",\ '%s' \)", class) > file
}
print last > file
return 1
}
# Load a template file
function db_load_template(file, this,name,tag,val,desc) {
debug(1,"# db_load_template %s", file)
while (!(eof=(getline < file) <= 0)) {
debug(6,"%s",$0)
if (match(tag,"^description") && match($0,"^ ")) {
sub("^","extended_",tag)
val = $0
sub("^ ","",val)
while (!(eof=((getline <file) <= 0)) && (match($0,"^ "))) {
sub("^ \\.$","\n"); sub("^ ","\n");
val = val $0
}
this[tag] = val
debug(6,"tag=%s, val=%s",tag,val)
}
if (eof || !NF) {
db_add(QDB, question_keywords, name, this)
db_add(TDB, template_keywords, name, this)
delete this
continue
}
if (match($0,"^[A-Z]")) { $1 = tolower($1) }
tag = $1; sub(":","",tag)
val = $0; sub(tag": ","",val); sub("^'","",val); sub("'$","",val)
# if (!template_keywords[tag]) {
# print "invalid keyword: "$0 > STDERR; break
# }
if (tag == "template") {
delete this
tag = "name"
name = val
}
debug(6,"this[%s]=%s",tag,val)
this[tag] = val
}
close(file)
return 1
}
function db_add(db,keywords,name,this, key,subvars) {
if (!name) return
for (key in this) {
subvars = subvars" "key
db_set_field(db, name, key, this[key])
debug(6,"db[%s]='%s'",name"=>"key,db[name"=>"key])
}
for (key in keywords) {
if ((key != "value") && (!db[name"=>"key])) {
db_set_field(db, name, key, "")
}
}
if ("flag_isdefault" in keywords) {
if (!db[name"=>flag_isdefault"]) {
db_set_field(db, name, "flag_isdefault", "true")
}
if (!db[name"=>template"]) {
db_set_field(db, name, "template", "$templates{'"name"'}")
db[name"=>template:type"] = "subst"
}
db[name":class"] = "Debian::DebConf::Question"
} else {
db[name":class"] = "Debian::DebConf::Template"
}
sub("^ ","",subvars)
db[name] = subvars
db[""] = db[""]" "name
}
function db_delete(db,keywords,name,this, key) {
for (key in db) {
if (match(key,"^"name"(=>|:)")) {
delete db[key]
}
}
if (name in db) {
delete db[name]
}
}
function db_set_field(db,name,key,val,type) {
if (!(name"=>"key in db)) {
db[name] = db[name]" "key
sub("^ ","",db[name])
}
db[name"=>"key] = val
if (type) {
db[name"=>"key":type"] = type
}
return val
}
function db_get_field(db,name,key) {
if (name"=>"key in db) {
db[":undef"] = 0
return db[name"=>"key]
} else {
db[":undef"] = 1
return ""
}
}
function db_get_value(db,name,default, val) {
if (!db_exists(db,name)) {
return(default)
}
val = db_get_field(db,name,"value")
if (db[":undef"]) {
return default
} else {
return val
}
}
function db_set_value(db,name,val,isdefault) {
if (!db_exists(db,name)) {
return
}
db_set_field(db,name,"value",val)
if (isdefault != "") {
db_set_field(db,name,"flag_isdefault",(isdefault ? "true" : "false"))
}
return val
}
function db_exists(db,name) {
if (name && (db_get_field(db,name,"name") == name)) {
db[":undef"] = 0
return 1
} else {
db[":undef"] = 1
return 0
}
}
# Returns 1 if the last db_get_field was unsuccessful
function db_undef(db) {
return (db[":undef"] == 1)
}
# end of file
# Question functions
#
# add_question(var,priority)
# delete_all_questions()
# ask_all_questions()
# nanoconf_priority(priority)
function add_question(var,p) {
debug(1,"# add_question %s %s",var,p)
# Noninteractive mode, questions not allowed except note and text
if (nanoconf["frontend"] == "noninteractive") {
if (!match(get_type(var),"(note|text)")) {
debug(2,"# noninteractive mode, ignored")
return 0
}
}
# Question priority less than debconf priority, question ignored
if (nanoconf_priority(p) < nanoconf_priority()) {
debug(2,"# low priority, ignored")
return 0
}
# If showold is not set don't show old questions
if ((nanoconf["showold"] != "true") && (!is_default(var))) {
debug(2,"# old question, ignored")
return 0
}
if (!active[var]) {
debug(2,"# added question %s %s %s",var,get_type(var),p)
nanoconf["active"] = nanoconf["active"]" "var
active[var] = p
}
return 1
}
function delete_all_questions() {
debug(1,"# delete_all_questions")
delete active
delete nanoconf["active"]
}
function ask_all_questions( var,n,i,_ask_questions) {
debug(1,"# ask_all_questions")
rc = 1
n = split(nanoconf["active"],_ask_questions)
for (i=1; i<=n; i++) {
var = _ask_questions[i]
if (!(rc = show_question(var))) {
debug(1,"# user backup: %s",var)
break
}
}
delete _ask_questions
return rc
}
function nanoconf_priority(p) {
if (!p) {
p = nanoconf["priority"]
}
if (p == "critical") { return 4 }
if (p == "high") { return 3 }
if (p == "medium") { return 2 }
if (p == "low") { return 1 }
return 0
}
# end of file
# Nanoconf frontend
#
# show_question(var)
# show_string(var,type)
# show_boolean(var,type)
# show_select(var,type)
# show_multiselect(var,type)
# show_note(var,type)
# show_text(var,type)
# show_password(var,type)
# mail_note(text,prompt)
# run_frontend(type,text,prompt,val,items)
# frontend_result()
# frontend_rc()
#
# Frontend interface:
#
# result = run_frontend(type,text,prompt,val,items)
#
# sets also the nanoconf["result"] and nanoconf["rc"] variables
#
# Items is an array with the following elements:
#
# items[""] = tags list
# items[tag] = item status (0 or 1), for multiselect
# items[tag:item] = optional text, normally not used
function show_question(var, type) {
type = or(get_type(var), "string")
debug(1,"# show_question %s %s",var,type)
if (type == "string") { rc = show_string(var,type) }
if (type == "password") { rc = show_password(var,type) }
if (type == "boolean") { rc = show_boolean(var,type) }
if (type == "select") { rc = show_select(var,type) }
if (type == "multiselect") { rc = show_multiselect(var,type) }
if (type == "note") { rc = show_note(var,type) }
if (type == "text") { rc = show_text(var,type) }
debug(2,"# rc=%s, %s=%s",rc,var,get_value(var))
return rc
}
function show_string(var,type, val) {
debug(1,"# show_string %s %s",var,type)
val = run_frontend(type, get_text(var), get_prompt(var), get_value(var))
if (frontend_rc() == 0) {
set_value(var,val,0)
return 1
} else {
return 0
}
}
# Handled by show_string()
function show_password(var,type) {
debug(1,"# show_password %s %s",var,type)
return show_string(var,type)
}
function show_boolean(var,type, val) {
debug(1,"# show_boolean %s %s",var,type)
val = run_frontend(type, get_text(var), get_prompt(var), get_value(var))
if (frontend_rc() >= 0) {
debug(1,"# booleean=%s", val)
set_value(var,val,0)
return 1
} else {
return 0
}
}
# Handles select and multiselect questions
function show_select(var,type, choices,val,n,_T) {
debug(1,"# show_select %s %s",var,type)
choices = get_field(var,"choices")
val = get_value(var)
n = split(choices,_T,",[ \t]*")
delete _T
if ((n==0) || ((n==1) && (type!="multiselect"))) {
debug(2,"# autoselect %s %s",n,choices)
set_value(var, choices, 0)
return 1
}
val = run_frontend(type, get_text(var), get_prompt(var), val, choices)
if (frontend_rc() != 0) {
return 0
}
debug(2,"# select=%s",val)
set_value(var, val, 0)
return 1
}
# Handled by show_select()
function show_multiselect(var,type) {
debug(1,"# show_multiselect %s %s",var,type)
return show_select(var,type)
}
function show_note(var,type, t) {
debug(1,"# show_note %s %s",var,type)
text = get_text(var)
prompt = get_prompt(var)
mail_note(text,prompt)
run_frontend(type,text,prompt)
if (frontend_rc() == 0) {
set_field(var,"flag_isdefault",0)
}
return 1
}
function show_text(var,type) {
debug(1,"# show_text %s %s",var,type)
run_frontend(type, get_text(var), get_prompt(var))
set_field(var,"flag_isdefault",0)
return 1
}
function mail_note(text,prompt) {
print "From nanoconf "date("+%a %b %e %T %Y") >> MBOX
print "Date: "date() >> MBOX
print "From: nanoconf <root at localhost>" >> MBOX
print "Subject: "quote(nanoconf["package"]) >> MBOX
print "" >> MBOX
print prompt >> MBOX
print text >> MBOX
print "" >> MBOX
close(MBOX)
}
function run_frontend(type,text,prompt,val,items) {
if (nanoconf["frontend"] == "dialog") {
return run_dialog_frontend(type,text,prompt,val,items)
} else {
return run_text_frontend(type,text,prompt,val,items)
}
}
# Returns result of last frontend run
function frontend_result() {
return nanoconf["result"]
}
# Returns rc of last frontend run (0=success)
function frontend_rc() {
return nanoconf["rc"]
}
# end of file
# Dialog frontend for nanoconf
#
# Frontend interface:
#
# result = run_frontend(type,text,prompt,val,items)
# rc = frontend_rc()
#
# sets also the nanoconf["result"] and nanoconf["rc"] variables
#
# Items is an array with the following elements:
#
# items[""] = tags list
# items[tag:item] = optional text, normally not used
# items[tag] = item status, 0 or 1
#
# whiptail usage:
#
# whiptail --yesno text height width
# whiptail --msgbox text height width
# whiptail --infobox text height width
# whiptail --inputbox text height width [init]
# whiptail --passwordbox text height width [init]
# whiptail --textbox file height width
# whiptail --menu text height width menuheight [tag item]...
# whiptail --checklist text height width listheight [tag item status]...
# whiptail --radiolist text height width listheight [tag item status]...
# whiptail --gauge text height width percent
#
# with:
#
# dialog = stdout
# result = stderr
# retcode = $?
#
# Example:
#
# val="$(whiptail --inputbox text 10 40 default 2>&1 </dev/tty >/dev/tty)"
# rc=$?
BEGIN {
setup_dialog_frontend()
}
function setup_dialog_frontend() {
if (test_x("/usr/bin/whiptail")) {
# Whiptail parameters
DLG["program"] = "whiptail"
DLG["bd"] = 5
DLG["bh"] = 6
DLG["sp"] = 1
DLG["ts"] = 10
DLG["cs"] = 3
# Mapping between debconf types and dialog types
DLG["string"] = "--inputbox"
DLG["password"] = "--passwordbox"
DLG["boolean"] = "--yesno"
DLG["select"] = "--menu"
DLG["multiselect"] = "--checklist"
DLG["note"] = "--msgbox"
DLG["text"] = "--infobox"
} else {
print "unable to find whiptail" > STDERR
exit 1
}
}
function run_dialog_frontend(type,text,prompt,val,choices, \
tw,th,w,h,m,n,i,s,rc,tag,_T,_V) {
debug(2,"# run_dialog_frontend %s, %s [%s]",type,prompt,val)
# Translate debconf var type to whiptail box type
type = or(DLG[type],"--inputbox")
if ((type == "note") && (nanoconf["frontend"] == "noninteractive")) {
type = "--infobox"
}
# Wrap text and compute text width
if (text && prompt) {
text = text"\n\n"prompt
} else {
text = prompt
}
tw = or(env("COLUMNS"),80)-DLG["bd"]-DLG["cs"]
th = or(env("ROWS"),25)-DLG["bh"]-2
text = wrap(text,tw)
h = split(text,_T,"\n")
for (w=i=1; i<=h; i++) { w = max(w,length(_T[i])) }; delete _T
# for dbugging very long text
# text = text"\n"text"\n"text"\n"text"\n"text"\n"text"\n"text"\n"text
# Compute menu item count
if (match(type,"(menu|checklist|radiolist)")) {
n = split(val,_T,",[ \t]*")
for (i=1; i<=n; i++) { _V[_T[i]] = 1 }
n = split(choices,_T,",[ \t]*")
}
# Compute dialog geometry
w = max(w,40)
h = max(h,1)
s = ((h>th) ? "--scrolltext" : "")
w = w+DLG["bd"]
h = min(h+n,th)
m = min(max(th-h-1,3),n)
h = h+DLG["bh"]
text = quote(text)
debug(3,"# tw=%s, th=%s, w=%s, h=%s, s=%s", tw,th,w,h,s)
if (DEBUG) { print "# text='"text"'" > STDERR } # debug printf limit is 1020
# Build the base command
cmd = sprintf("%s --backtitle %s --title %s %s %s", DLG["program"], \
quote(nanoconf["backtitle"]), quote(nanoconf["title"]),
s, type)
debug(5,"# cmd=%s.",cmd)
# Add val option for checklists
if (match(type,"checklist")) { cmd = cmd" --separate-output" }
# Add text and base geometry
cmd = cmd" "text" "h" "w
# Add val argument where allowed
if (match(type,"(yesno|inputbox|gauge)")) {
if (match(type,"yesno")) {
if (val != "true") { val = "--defaultno" }
}
if (match(type,"gauge")) {
val = max(min(val,100),0)
}
if (val) { cmd = cmd" "quote(val) }
}
# Add menu height and items. Note that m could be less than n
if (match(type,"(menu|checklist|radiolist)")) {
cmd = cmd" "m
# Put default menu value first
if (match(type,"menu") && (val!="")) {
cmd = cmd" "quote(val)" ''"
}
for (i=1; i<=n; i++) {
tag = _T[i];
if (match(type,"menu") && (tag==val)) continue
s = ((tag in _V) ? "on" : "off")
cmd = cmd" "quote(tag)" ''"
if (!match(type,"menu")) {
cmd = cmd" "s
}
}
}
# Redirect dialog input and output
cmd = cmd" <"TTY" >"TTY" 2>"TEMPFILE
# Run the dialog command
printf "" > TEMPFILE
result = ""
rc = run(cmd)
# Interpret the result
# if (match(type,"(msgbox|textbox|gauge")) {
# }
if (match(type,"infobox")) {
system("sleep 1")
rc = 1
}
if (match(type,"yesno") && (rc >= 0)) {
result = ((rc == 0) ? "true" : "false")
}
if (match(type,"(inputbox|passwordbox|menu|checklist|radiolist)")) {
if (rc == 0) {
result = readfile(TEMPFILE)
if (match(type,"checklist")) {
m = split(result, _T, "\n")
result = ""
for (i=1; i<=m; i++) {
result = result", "_T[i]
}
sub(", ","",result)
delete _T
}
}
}
debug(2,"# rc=%s, result=%s",rc,result)
nanoconf["result"] = result
nanoconf["rc"] = rc
return result
}
# end of file
# Text frontend for nanoconf
#
# Frontend interface:
#
# result = run_frontend(type,text,prompt,val,items)
# rc = frontend_rc()
#
# sets also the nanoconf["result"] and nanoconf["rc"] variables
#
# Items is an array with the following elements:
#
# items[""] = <item tag list>
# items[tag] = <item text>
# items[s:tag] = <item status>
function run_text_frontend(type,text,prompt,val,choices, \
tw,m,n,i,s,tag,x,rc,_T,_V) {
debug(2,"# run_text_frontend %s %s",type,prompt)
# Display title only for the first time
if (nanoconf["title"] && TXT["title"] != nanoconf["title"]) {
TXT["title"] = nanoconf["title"]
print "" > TTY
print nanoconf["title"] > TTY
l = length(TXT["title"])
for (i=1; i<=l; i++) { printf("=") > TTY }
print "" > TTY
}
print "" > TTY
# Shortcut for note and text questions
if (match(type,"(note|text)")) {
print prompt > TTY
print text > TTY
print "" > TTY
if ((type == "note") && (nanoconf["frontend"] != "noninteractive")) {
printf("Press ENTER...") > TTY; getline x < TTY
nanoconf["rc"] = 0
return 0
} else {
nanoconf["rc"] = 1
return 1
}
}
# Print the extended description first
tw = or(env("COLUMNS"),80)
print wrap(text,tw) "\n" > TTY
# Print available choices for select and multiselect questions
if (match(type,"(select|multiselect)")) {
n = split(val,_T,",[ \t]*")
for (i=1; i<=n; i++) { _V[_T[i]] = 1 }
n = split(choices,_T,",[ \t]*")
m = 1
# Print default menu value first
if ((type=="select") && (val!="")) {
printf("%4s %s\n",0,val) > TTY
_T[0] = val
m = 0
}
for (i=1; i<=n; i++) {
tag = _T[i]
if (type == "multiselect") {
s = ((tag in _V) ? "[*]" : " ")
}
printf("%4s %s %s\n",i,s,tag) > TTY
}
if (type == "multiselect") {
printf("%4s %s %s\n","n"," ","<none>") > TTY
}
print "" > TTY
}
# Loop until a valid answer is received
while (1) {
result = ""
rc = 0
# Print prompt and current value
if (type == "string") {
printf("%s [%s] ", prompt, val) > TTY
}
if (type == "password") {
printf("%s ", prompt) > TTY
run("stty -echo <"TTY)
}
if (type == "boolean") {
printf("%s [%s] ", prompt, ((val=="true") ? "Y/n" : "N/y")) > TTY
}
if (match(type,"(select|multiselect)")) {
printf("%s ", prompt) > TTY
}
# Read user input
rc = ((getline answer < TTY) == 1) - 1
if (type == "password") {
run("stty echo <"TTY)
print "" > TTY
}
if (rc < 0) {
break
}
if (type == "string") {
result = ((answer != "") ? answer : val)
break
}
if (type == "password") {
result = answer
if (result != "") {
break
}
}
if (type == "boolean") {
answer = tolower(answer)
if (match(answer,"^y(es)?$")) { result = "true"; break }
if (match(answer,"^no?$")) { result = "false"; break }
if ((answer == "") && (val)) { result = val; break }
}
if (type == "select") {
if (answer == "") answer = 0
if ((answer>=m) && (answer<=n)) { result = _T[answer]; break }
}
if (type == "multiselect") {
if (answer == "") {
result = val
break
}
if (match(answer,"^[Nn]$")) {
break
}
errors = 0
x = split(answer,_V,"[, \t]+")
for (i=1; (i<=x); i++) {
v = _V[i]
if ((v>=m) && (v<=n)) {
result = result", "_T[v]
} else {
errors++
}
}
sub(", ","",result)
if (!errors) break
}
# Invalid answer, loop again
}
debug(2,"# rc=%s, result=%s",rc,result)
nanoconf["result"] = result
nanoconf["rc"] = rc
return result
}
# end of file
# Debug commands
($1 == "dump") { cmd_dump($2,$3); next }
($1 == "show") { cmd_show($2,$3); next }
($1 == "del") { cmd_del($2,$3); next }
function cmd_dump(which,expr) {
if (!expr) { expr=which; which="" }
if (!which || (match("templates","^"which))) {
parray(TDB,"templates","",expr)
}
if (!which || (match("questions","^"which))) {
parray(QDB,"questions","",expr)
}
}
function cmd_show(which,expr, key) {
if (!expr) { expr=which; which="" }
if (!which || (match("templates","^"which))) {
if (key in templates) {
parray(TDB,"templates","","^"expr"$")
}
}
if (!which || (match("questions","^"which))) {
if (key in questions) {
parray(QDB,"questions","","^"expr"$")
}
}
}
function cmd_del(which,name) {
if (!expr) { expr=which; which="" }
if (!which || (match("templates","^"which))) {
db_delete(TDB,name)
}
if (!which || (match("questions","^"which))) {
db_delete(QDB,name)
}
}
# end of file
--
see shy jo
More information about the Crackmonkey
mailing list