From: David Lecompte <3gpp@metani.eu> Date: Mon, 1 Jun 2026 15:32:43 +0000 (+0200) Subject: Initial addition of tools used on Trisquel GNU/Linux. X-Git-Url: https://nuage.metani.fr/gitweb/3GPP.git/commitdiff_plain/5a64e60ec186f693ccb704467424a8a485e45c94 Initial addition of tools used on Trisquel GNU/Linux. --- 5a64e60ec186f693ccb704467424a8a485e45c94 diff --git a/awk/txt2asn-integrated.awk b/awk/txt2asn-integrated.awk new file mode 100644 index 0000000..a4f1acf --- /dev/null +++ b/awk/txt2asn-integrated.awk @@ -0,0 +1,487 @@ +#!/bin/gawk + +# Arrays used: + +# Information about each ASN.1 line, indexed by number + +# text: the complete line +# field: the field, without suffix (if there is one) +# structure: the outer structure (if it is a field) +# condition: the condition, if there is one + +# Information about each field description, indexed by outer structure and field name (when a description is for a coma-separated list of fields, a separate entry is created for each field). + +# field_description_len: how many descriptions lines (0 means none) +# field_description: the lines of a field descritpion, indexed from 1 + +function asn1_print() +{ + + if (!(1 in text)) { return ; } + #print "entering asn1_print"; + for (line=1; line<=line_number; line++) { + #if (field[line] != "") { + # print "Ligne " line " champs " field[line] ; + # print "Structure " structure[line] ; + # print "Description de longueur " field_description_len[structure[line]][field[line]]; + #} + if (((field[line] != "") && + (field_description_len[structure[line]][field[line]] > 0)) || + ((condition[line] != "") && + (condition_description_len[condition[line]] > 0))) { + + indentation = ""; + position = index(text[line], field[line]) - 1; + + #print "ligne " line " position " position " field " field[line] " structure " structure[line]; + indentation = ""; + for (i=0;i 0) { + for (i=1;i<=field_description_len[structure[line]][field[line]]; i++) { + + print indentation "-- " field_description[structure[line]][field[line]][i]; + + } + } + + if (condition_description_len[condition[line]] > 0) { + if(field[line] != "") + { + for(i=1;i<=condition_description_len[condition[line]];i++) { + gsub(/(, )*[Nn]eed [MNSR],*/, "", condition_description[condition[line]][i]); + print indentation "--" condition_description[condition[line]][i]; + } + } + + + if (condition_code[condition[line]] == "") + { sub(/-- Cond [A-Za-z0-9_-]+/, "", text[line]); } + else + { sub(/-- Cond [A-Za-z0-9_-]+/, "-- Need " condition_code[condition[line]], text[line]); } + } + + print text[line] ; + + + } + + else { + if (text[line] ~ /-- Cond [A-Za-z0-9_-]+/) + { + #print "trouvé"; + if (condition_code[condition[line]] == "") + { sub(/-- Cond [A-Za-z0-9_-]+/, "", text[line]); } + else + { + #print "Ligne " text[condition_reference[line]]; + #print "Condition " ; + sub(/-- Cond [A-Za-z0-9_-]+/, "-- Need " condition_code[condition[line]], text[line]); } + } + #if((line>0) || (text[line] ~ /[a-zA-Z0-9-]/)) { + print text[line] ; + #} + } + } + + delete text; + delete text_level; + delete field; + delete structure; + delete condition; + delete field_description_len; + delete field_description; + delete condition_description_len; + delete condition_description; + delete condition_code; + delete condition_reference; + + #print "end of asn1_print" +} + +function need_code(aaa) +{ + if (aaa ~ /[Nn]eed M[ ,.]/) { return "M" } + if (aaa ~ /[Nn]eed N[ ,.]/) { return "N" } + if (aaa ~ /[Nn]eed R[ ,.]/) { return "R" } + if (aaa ~ /[Nn]eed S[ ,.]/) { return "S" } + return "" +} + +function level(bbb) +{ + local_bbb1 = bbb + local_bbb2 = bbb + return gsub(/{/, "", local_bbb1) - gsub(/}/, "", local_bbb2) +} + +BEGIN { + add_line_after != "" ; + separator = "" ; + + wide_separator = "" ; + for(i=0;i<=140;i++) { + wide_separator = wide_separator "-" ; + } + + ie_separator = "-- " ; + for (i=0;i<=137;i++) { + ie_separator = ie_separator "=" ; + } + +} + +/^[0-9]+\./ { + if (in_IE == "yes") { asn1_print(); } + in_IE = "no" ; +} + +/^-- ASN1START/ { + print ""; + in_ASN1 = "yes"; + line_number = 0; + #empty_line = "yes"; + next; +} + +/^-- ASN1STOP/ { + in_ASN1 = "no"; + next; +} + +/^-- TAG-/ { + next; +} + +/^[[:space:]]*$/ { + + if (next_line == "condition") { + #print separator ; + } + if ((next_line == "field description") || (next_line == "field name")){ + #print separator ; + } + + next_line = "" ; +# #if (empty_line == "yes") { +# next; +# } + + current_condition = "" ; + if (empty_line == "yes") { next; } + empty_line = "yes" ; + + + #print "empty_line set to yes" ; +# print ; +} + +/\S/ { + + # The empty_line condition is meant for what is directly printed, i.e. messages decriptions + # ASN.1, field descriptions and conditions descriptions are not directly printed, so + # this should not apply to them + + + + #if ((next_line == "field description") || (next_line == "field name")){ + empty_line = "no" ; + #print "empty_line set to no" + #} + +} + +/^–[[:space:]]+ParentIE-WithEM$/ { + exit 0 ; +} + +/^–[[:space:]]+[A-Za-z0-9-]+$/ { + asn1_print(); + +# if (empty_line == "yes") { + #print ""; + print ie_separator; + print "-- IE: " $2; + print "" ; + empty_line = "no" ; + conditions = "" ; + IE_name = $2; + + #if (IE_name == "PosSI-SchedulingInfo") { print "IE trouvé" ; } +# } + in_IE = "yes" ; + + next ; +} + +/^Conditional [Pp]resence/ { + add_line_after = ""; + separator = "" ; + + $0 = "Conditional presence" ; + for(i=0;i<=140;i++) { + separator = separator "-" ; + } +# print separator; + #add_line_after = separator ; + next_line = "condition" ; + #print "Conditional Presence" + #if (IE_name == "PosSI-SchedulingInfo") { print "condition trouvée" ; } +} + +# Need to catch "x and y field descriptions" + +/field descriptions$/ { + add_line_after = ""; + separator = "" ; + + for(i=0;i<=140;i++) { + separator = separator "-" ; + } +# print separator; +# add_line_after = separator ; + next_line = "field name" ; + + field_struct = $1; + + #print "Trouvé description des champs de " $1; + # do not print + next; +} + +#/^[A-Za-z0-9-]+[[:space:]]+[A-Za-z0-9-]+/ { +# if (next_line == "field description") { +# add_line_after = separator ; +# next_line = "field name"; +# } +#} + +# This is matched for any non-empty line +/^[A-Za-z0-9-]+/ { + + + if ((in_IE == "yes") && (in_ASN1 == "no")){ + + # if we are coming from a "IE X field description" statement + # or we were in a field description + if ((next_line == "field name") || (next_line == "field description")) { + + + # If the whole line is a coma-separated list in an IE (=> field names) + if (/^[A-Za-z0-9-]+(, [A-Za-z0-9-]+)*$/) { + # Then, this is a new field, or list of fields + #print separator ; + + names = $0; + + # remove leading/trailing spaces + sub(/^[[:space:]]+/, "", names); + sub(/[[:space:]]+$/, "", names); + + # remove comas and duplicate spaces + gsub(/,/, "", names); + gsub(/[[:space:]]+/, " ", names); + + #print "coucou " names; + #print $0; + + delete field_list; + # this will delete any previous field_list + ret = split(names, field_list, " "); + + #print "hello"; + #print "split returned " ret ; + #for (abc in field_list) + #{ print "field_list contient " field_list[abc];} + + + $0 = "Field: " $0 + #add_line_after = " "; + + # Add one entry for each of the fields + for (ii in field_list) { + num = field_description_len[field_struct][field_list[ii]] = 0; + #print "Trouvé description de " field_list[ii]; + } + + if (next_line == "field name") { + next_line = "field description"; + } + + else { next_line = "field name" ; } + next; + } + + else { + # This is a field description + #print "coucou"; + #if (index($0,"BAP")!=0) { + #print "BAP trouvé" $0 ; + #} + #print "contenu " $0; + + if ((next_line == "field name") || (next_line == "field description")) { + for (ii in field_list) { + field_description_len[field_struct][field_list[ii]]++; + num = field_description_len[field_struct][field_list[ii]]; + field_description[field_struct][field_list[ii]][num] = $0; + #print "ajouté une ligne pour " field_list[ii] "dans " field_struct; + } + next; + } + } + } + } +} + +#/^[A-Za-z0-9-]+/ { +# # remove suffix +# sub(/-[vr][0-9]+$/, "", $1); +# +# current_structure = $1 ; +#} + + + +{ + if (in_IE == "yes") { + + #print "$0 est " $0 " in_ASN1 est " in_ASN1; + if (next_line == "condition") { + #print "branche condition " $0; + if ($1 != "Conditional") { + if (index(conditions, $1) != 0) { + current_condition = $1 ; + condition_description_len[current_condition] = 1 ; + $1 = "" ; + condition_description[current_condition][1] = $0 ; + condition_code[current_condition] = need_code($0); + + #print separator; + #print "-- Condition: " $1; + + #print "Condition " current_condition " trouvée"; + } + + + #if ((in_ASN1 == "no") && !(/^\s*$/)) { + #$0 = "-- " $0 ; + #} + + # prints first line of condition + #print $0 " aaa"; + + + else { + #print "La description est " $0; + condition_description_len[current_condition]++; + condition_description[current_condition][condition_description_len[current_condition]] = $0 ; + condition_code[current_condition] = need_code($0); + } + } + } + else { + + #print "in_ASN1 est " in_ASN1 " ligne " $0; + if ((in_ASN1 == "no") && !(/^\s*$/)) { + $0 = "-- " $0 ; + #print $0 " bbb"; + } + + if (in_ASN1 == "no") { + + # prints subsequent lines of condition or IE description + if ((!(/\S/) && (empty_line == "yes"))) {next} + print $0 #" ccc"; + + } + else { + #print line_number; + if((line_number==0) && (/^[[:space:]]*$/)) { next ; } + line_number++; + text[line_number] = $0; + + #print "text[" line_number "] est " text[line_number]; + if (/^[A-Za-z0-9-]+[[:space:]]+:/) { + # remove suffix + sub(/-[vr][0-9]+(-IEs)*$/, "", $1); + #print "ddd" ; + current_structure = $1 ; + text_level[line_number] = level(text[line_number]); + + #print $1; + } + else { + + if (/[[:space:]]+[a-z][A-Za-z0-9-]*/) { + text_level[line_number] = text_level[line_number-1] + level(text[line_number]) ; + + # remove suffix + sub(/-[vr][0-9]+$/, "", $1); + # remove ToAddModList extension suffixes + sub(/ToAddModListExt/, "ToAddModList", $1); + sub(/ToAddModListSizeExt/, "ToAddModList", $1); + + field[line_number] = $1; + + #print "field est " field[line_number]; + structure[line_number] = current_structure ; + field_description_len[current_structure][$1] = 0; + + + } + else { + field[line_number] = ""; + text_level[line_number] = text_level[line_number-1] + level(text[line_number]) ; + } + + if (/-- Cond [A-Za-z0-9_-]+$/) { + if(/}\s*(OPTIONAL)*,*\s*-- Cond [A-Za-z0-9_-]+$/) { + #print "trouvé" ; + + # The condition should be placed above the field name, + # It is something like + # field0 ..... level X + # field1 { ..... level X+1 + # abc ABC, ..... level X+1 + # def DEF ..... level X+1 + # } OPTIONAL, -- Cond XYZ ..... level X + # So we go back up while level > level of the Cond line + # Then we reach field0, so this is the line after + # We then associate that line with the condition + + for (b=1;text_level[line_number-b]>text_level[line_number];b++) {}; + condition[line_number-b+1] = $ NF ; + + # Still, to replace -- Cond XXX with - Need M/R/N, + # we need to know the line associated with the condition + condition_reference[line_number] = line_number-b+1; + } + + condition[line_number] = $NF ; + + #print "condition[" line_number "] est " condition[line_number] + } + else { + condition[line_number] = ""; + } + } + } + } + if (add_line_after != "") { + print add_line_after ; + add_line_after = "" ; + } + + if (/-- Cond [A-Za-z0-9_-]+$/) { + conditions = conditions " " $NF ; + } + } +} + diff --git a/awk/txt2asn.awk b/awk/txt2asn.awk new file mode 100644 index 0000000..0c022e0 --- /dev/null +++ b/awk/txt2asn.awk @@ -0,0 +1,159 @@ +#!/bin/gawk + +BEGIN { + add_line_after != "" ; + separator = "" ; + + wide_separator = "" ; + for(i=0;i<=140;i++) { + wide_separator = wide_separator "-" ; + } + + ie_separator = "-- " ; + for (i=0;i<=137;i++) { + ie_separator = ie_separator "=" ; + } +} + +/^[0-9]+\./ { + in_IE = "no" ; +} + +/^-- ASN1START/ { + print ""; + in_ASN1 = "yes"; + next; +} + +/^-- ASN1STOP/ { + in_ASN1 = "no"; + next; +} + +/^-- TAG-/ { + next; +} + +/^[[:space:]]*$/ { + + if (next_line == "condition") { + print separator ; + } + if ((next_line == "field description") || (next_line == "field name")){ + print separator ; + } + + next_line = "" ; +# #if (empty_line == "yes") { +# next; +# } + empty_line = "yes" ; + +# print "a" ; +# print ; +} + +/^–[[:space:]]+ParentIE-WithEM$/ { + exit 0 ; +} + +/^–[[:space:]]+[A-Za-z0-9-]+$/ { + if (empty_line == "yes") { + print ie_separator; + print "-- IE: " $2; + print "" ; + empty_line = "no" ; + conditions = "" ; + } + in_IE = "yes" ; + next ; +} + +/^Conditional Presence/ { + add_line_after = ""; + separator = "" ; + + $0 = "Conditional presence" ; + for(i=0;i<=140;i++) { + separator = separator "-" ; + } +# print separator; + #add_line_after = separator ; + next_line = "condition" ; +} + +# Need to catch "x and y field descriptions" + +/field descriptions$/ { + add_line_after = ""; + separator = "" ; + + for(i=0;i<=140;i++) { + separator = separator "-" ; + } +# print separator; +# add_line_after = separator ; + next_line = "field name" ; +} + +#/^[A-Za-z0-9-]+[[:space:]]+[A-Za-z0-9-]+/ { +# if (next_line == "field description") { +# add_line_after = separator ; +# next_line = "field name"; +# } +#} + +/^[A-Za-z0-9-]+(, [A-Za-z0-9-]+)*$/ { + if (next_line == "field name") { + + print separator ; + + $0 = "Field: " $0 + #add_line_after = " "; + next_line = "field description"; + } + else if (next_line == "field description") { + print separator ; + + $0 = "Field: " $0 + #add_line_after = separator ; + #print "separator est " separator; + next_line = "field name"; + } +} + + + +{ + if (in_IE == "yes") { + if ((next_line == "condition") && ($1 != "Conditional")) { + + if (index(conditions, $1) != 0) { + print separator; + print "-- Condition: " $1; + $1 = ""; + } + if ((in_ASN1 == "no") && !(/^\s*$/)) { + $0 = "-- " $0 ; + } + print ; + } + + else { + if ((in_ASN1 == "no") && !(/^\s*$/)) { + $0 = "-- " $0 ; + } + print; + } + + if (add_line_after != "") { + print add_line_after ; + add_line_after = "" ; + } + + if (/-- Cond [A-Za-z0-9-]+$/) { + conditions = conditions " " $NF ; + } + } +} + diff --git a/bin/docx2asn b/bin/docx2asn new file mode 100755 index 0000000..7618cb8 --- /dev/null +++ b/bin/docx2asn @@ -0,0 +1,55 @@ +#!/bin/bash + +if [[ $# -eq 0 ]] ; then + echo "Usage: ${0##*/} file [files]" + echo "Extract ASN.1 from one or more 3GPP 38.331 docx files and save then to .asn files" + exit 1 +fi + +if [[ ! -w . ]] ; then + echo "Cannot write to current directory" + exit 1 +fi + +if [[ ! -x $(which libreoffice) ]] ; then + echo "Cannot find executable libreoffice" + exit 1 +fi + +while [ "$#" -gt 0 ]; do + + echo "Processing parameter: $1" + + if [[ ! -f "$1" ]] || [[ ! -r "$1" ]] ; then + echo "$1 is not a readable file" + shift + continue + fi + + if [[ -e "${1%.docx}.txt" ]] ; then + echo "${1%.docx}.txt already exists: skipping conversion" + + else + libreoffice --convert-to txt "$1" + + if [[ ! -f "${1%.docx}.txt" ]] || [[ ! -r "${1%.docx}.txt" ]] ; then + echo "libreoffice did not create ${1%.docx}.txt" + shift + continue + fi + fi + + if [[ -e "${1%.docx}.asn" ]] ; then + echo "${1%.docx}.asn already exists: not regenerated" + shift + continue + fi + + cat "${1%.docx}.txt" | awk '/^-- ASN1START$/,/^-- ASN1STOP$/' | grep -Evxe '-- ASN1ST(ART|OP)' | grep -v '^--' | awk 'NF || p; { p = NF }' p=0 > "${1%.docx}.asn" + + if [[ -e "${1%.docx}.asn" ]] ; then + echo "${1%.docx}.asn was generated" + fi + shift +done +