diff --git a/cdist/conf/type/__ini_value/explorer/state b/cdist/conf/type/__ini_value/explorer/state new file mode 100755 index 00000000..1808d90e --- /dev/null +++ b/cdist/conf/type/__ini_value/explorer/state @@ -0,0 +1,152 @@ +#!/bin/sh -e +# __ini_value/explorer/state + +# Check the state of the key-value pair in the ini file +# +# There are following states: +# - present +# - wrongvalue +# - wrongformat +# - commented +# - absent +# - nosuchfile + +# Using ' \t' for matching spaces as char classes not implemented in mawk +# see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=65617#40 + +# Parameters +# (maybe multi-variable object id for this ..) +#state_should="$(cat "$__object/parameter/state")" +file="$(cat "$__object/parameter/file")" + +# abort if no file exist +if ! [ -f "$file" ]; then + echo nosuchfile + exit +fi + +# run awk +awk -f - "$file" <<'AWK' +function trim(var) { + sub(/^[ \t]*/, "", var) + sub(/[ \t]*$/, "", var) + return var +} +function check_spaces(var) { + return match(var, /^[ \t]*$/) == 1 +} +function state(val) { + print val + exit +} + +BEGIN { + _param = (ENVIRON["__object"] "/parameter/") + getline state_should < (_param "state") + getline section < (_param "section") + getline key < (_param "key") + getline delimiter < (_param "delimiter") + getline value < (_param "value") + getline indentation < (_param "indentation") + + do_normalization = (system("test -f " (_param "normalize")) == 0) + + i=0; _comm_param = (_param "comment-sign"); + while((getline tmp < _comm_param) > 0) { + comment_signs[i++] = tmp + } + + found=0 + curr_section="" + if(section == "") + found_section=1 + else + found_section=0 +} + +# catch sections +/^[ \t]*\[.*\][ \t]*$/ { + curr_section = trim($0) + if(found_section) + exit # game over, section ends + if(section == curr_section) + found_section=1 + next +} + +# only interesting if a delimiter was found +found_section { + line = $0 + + # index 1 cause of trimmed string + if((idel = index(line, delimiter)) && (ikey = index(line, key))) { + if(ikey > 1) { + # maybe comment character or only spaces + start_string = substr(line, 1, ikey - 1) + + # something inside rather than a space -> comment + if((icom = match(start_string, /[^ \t]+/)) > 0) { + # icom = RSTART + # only one free-standing char or directly before the key + if(RLENGTH == 1 || icom == ikey - 1) { + start_sign = substr(line, RSTART, 1) + is_com=0 + for(i in comment_signs) { + if(start_sign == comment_signs[i]) { + is_com = 1; break; + } + } + if(!is_com) next + else { + aftercom_length = ikey - icom - 1 + if(!check_spaces(substr(line, icom + 1, aftercom_length))) next + start_spaces = (icom - 1) + aftercom_length + } + } + else next + } + # must only contain spaces + else start_spaces = ikey - 1 + } + # start_spaces set or 0 + + idelspace_start = ikey + length(key) + idelspace_length = idel - (idelspace_start) + # check for delimiter is only preceded with spaces + if(idelspace_length == 0 || check_spaces(substr(line, idelspace_start, idelspace_length))) { + found = 1 + + # short-circuit on state absent to just delete + if(state_should == "absent") state("present"); + + + # extract the value + found_value = substr(line, idel + length(delimiter)) + is_value = trim(found_value) + + # check if value is incorrect + if(value != is_value) state("wrongvalue") + else { + # check if the format is important + if(do_normalization) { + # the format must exactly match, else it is incorrect + if(indentation != start_spaces || idelspace_length != 0 || found_value != is_value) + state("wrongformat") + } + + if(is_com) + state("commented") + else + state("present") + } + # this will never be reached + } + } +} + +# in the end, check if it is absent +END { + if(!found) + state("absent") +} +AWK diff --git a/cdist/conf/type/__ini_value/files/base.awk b/cdist/conf/type/__ini_value/files/base.awk new file mode 100644 index 00000000..16ff5808 --- /dev/null +++ b/cdist/conf/type/__ini_value/files/base.awk @@ -0,0 +1,128 @@ +BEGIN { + #bufindex = 0 + #maxbuflen = 2 + + # no section means the start to the first section + if(section == "") { + is_curr_section = 1 + found_section = 1 + } +} + +# legacy function +function flush_buffer() { + #while(bufindex > 0) { + # _pop_buffer() + #} + if(lastlinepopulated) { + print lastline + lastlinepopulated = 0 + } +} + +# excepts the first character is the sign to check (string is trimmed) +function is_comment(line) { + # get character and check + line_sign = substr(line, 1, 1) + for(i in comment_signs) + if(line_sign == comment_signs[i]) + return 1 + + # nothing found + return 0 +} +function was_comment(line, comment) { + line = trim(line) + if(is_comment(line)) { + return trim(substr(line, 2)) == comment + } +} + +# print everything if line found instead of processing it +# maybe just a function to loop through getline for lightest overhead +found {print; next} + +# main loop (til the line was found) +!found { + line = trim($0) + # short curcit on empty lines + if(line == "") { + # TODO code to function! + flush_buffer() + lastline = $0 + lastlinepopulated = 1 + next + } + + # write to linebuffer + #if(bufindex > maxbuflen) + # _pop_buffer() + #linebuffer[++bufindex] = $0 + + # check for a ini section + if(substr(line, 1, 1) == "[" && substr(line, length(line), 1) == "]") { + is_section = 1 + curr_section = line + + if(curr_section == section) { + found_section = 1 + is_curr_section = 1 + } + else { + # if nothing found, print it in the valid section before the next one + if(is_curr_section) { + if(!found) { + # set found as it is there now + found=1 + + # %codeblock_insert% + } + is_curr_section = 0 + } + } + } + else { + # only current session is interessting + if(is_curr_section) { + # check for a comment + is_com = is_comment(line) + if(is_com) { + line = trim(substr(line, 2)) + } + + # check for a delimiter and a key (must be at first position due to trimming) + if((idel = index(line, delimiter)) && (ikey = index(line, key)) == 1) { + # check there are only spaces between the delimiter + if(check_spaces(substr(line, ikey + length(key), idel - (length(key) + 1)))) { + found = 1 + + # %codeblock_found% + + next + } + } + } + } + + # TODO + # works cause no next statement from above *structual programming* + #print lastline + flush_buffer() + lastline = $0 + lastlinepopulated = 1 +} + +END { + # if not found, it's not already printed + if(!found) { + flush_buffer() + + # print with section if not found + if(!found_section) { + # TODO check via buffer if a empty line is necessary + print section + + # %codeblock_insert% + } + } +} diff --git a/cdist/conf/type/__ini_value/files/common.awk b/cdist/conf/type/__ini_value/files/common.awk new file mode 100644 index 00000000..8874f0b8 --- /dev/null +++ b/cdist/conf/type/__ini_value/files/common.awk @@ -0,0 +1,61 @@ +BEGIN { + # parameter variables + section = get_param_string("section") + key = get_param_string("key") + delimiter = get_param_string("delimiter") + value = get_param_string("value") + comment = get_param_string("comment") + indentation = get_param_string("indentation") + + get_param_array("comment-sign", comment_signs) + comment_sign = comment_signs[0] +} + +function trim(var) { + sub(/^[ \t]*/, "", var) + sub(/[ \t]*$/, "", var) + return var +} +function check_spaces(part) { + return match(part, /^[ \t]*$/) == 1 +} + +function get_param_string(name) { + _paramfile = (ENVIRON["__object"] "/parameter/" name) + if((getline tmp < _paramfile) > 0) { + close(_paramfile) + return tmp + } + else return "" +} +function get_param_array(name, arr) { + _paramfile = (ENVIRON["__object"] "/parameter/" name) + i=0 + split("", arr) # portable clear, like `delete arr` + while((getline tmp < _paramfile) > 0) { + arr[i++] = tmp + } + close(_paramfile) +} + +# print value +function v_print() { + spaces = "" + for(i = 0; i < indentation; i++) + spaces = (spaces " ") + printf "%s%s%s%s%s", spaces, key, delimiter, value, ORS +} +# print commented value +function v_print_commented() { + spaces = "" + for(i = 0; i < indentation; i++) + spaces = (spaces " ") + printf "%s%s%s%s%s%s", spaces, comment_sign, key, delimiter, value, ORS +} +# print comment +function c_print() { + spaces = "" + for(i = 0; i < indentation; i++) + spaces = (spaces " ") + printf "%s%s%s%s%s", spaces, comment_sign, " ", comment, ORS +} diff --git a/cdist/conf/type/__ini_value/files/gen-awk.sh b/cdist/conf/type/__ini_value/files/gen-awk.sh new file mode 100755 index 00000000..ba26672a --- /dev/null +++ b/cdist/conf/type/__ini_value/files/gen-awk.sh @@ -0,0 +1,53 @@ +#!/bin/sh -e +# __ini_value/files/gen-awk.sh + +# Generates the awk script that will modify the line +# +# Arguments: +# 1: the file to modify +# 2: the should_state + +strip_comments() { + grep -v '^[[:space:]]*\($\|#\)' +} + + +file="$1" +state="$2" + + +# Generate the basic awk struct +cat < "\$tmpfile" <<'AWK' +SHELL + + +# generate the awk script and strip unnecessary things +{ + # basic functions which everyone needs + cat "$__type/files/common.awk" + + # generate the script and strip + awk -v state="$state" ' + { + if(match($0, /^[ \t]*# %codeblock_([^%]+)%$/, result) > 0) { + file = (ENVIRON["__type"] "/files/parts/" state "/" result[1] ".awk") + while((getline line < file) > 0) + print line + close(file) + } + else print + }' "$__type/files/base.awk" +} | strip_comments + + +# end of here-doc +cat <&2 + exit 1 + ;; +esac diff --git a/cdist/conf/type/__ini_value/parameter/boolean b/cdist/conf/type/__ini_value/parameter/boolean new file mode 100644 index 00000000..f9a8b6aa --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/boolean @@ -0,0 +1 @@ +normalize diff --git a/cdist/conf/type/__ini_value/parameter/default/comment-sign b/cdist/conf/type/__ini_value/parameter/default/comment-sign new file mode 100644 index 00000000..406ac1cc --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/default/comment-sign @@ -0,0 +1,2 @@ +; +# diff --git a/cdist/conf/type/__ini_value/parameter/default/indentation b/cdist/conf/type/__ini_value/parameter/default/indentation new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/default/indentation @@ -0,0 +1 @@ +0 diff --git a/cdist/conf/type/__ini_value/parameter/default/state b/cdist/conf/type/__ini_value/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__ini_value/parameter/optional b/cdist/conf/type/__ini_value/parameter/optional new file mode 100644 index 00000000..031c807b --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/optional @@ -0,0 +1,6 @@ +section +key +state +value +indentation +comment diff --git a/cdist/conf/type/__ini_value/parameter/optional_multiple b/cdist/conf/type/__ini_value/parameter/optional_multiple new file mode 100644 index 00000000..bac05165 --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/optional_multiple @@ -0,0 +1 @@ +comment-sign diff --git a/cdist/conf/type/__ini_value/parameter/required b/cdist/conf/type/__ini_value/parameter/required new file mode 100644 index 00000000..3ae10da3 --- /dev/null +++ b/cdist/conf/type/__ini_value/parameter/required @@ -0,0 +1,2 @@ +file +delimiter