]> nuage.metani.fr Git - 3GPP.git/commitdiff
Initial addition of tools used on Trisquel GNU/Linux.
authorDavid Lecompte <3gpp@metani.eu>
Mon, 1 Jun 2026 15:32:43 +0000 (17:32 +0200)
committerDavid Lecompte <3gpp@metani.eu>
Mon, 1 Jun 2026 15:32:43 +0000 (17:32 +0200)
awk/txt2asn-integrated.awk [new file with mode: 0644]
awk/txt2asn.awk [new file with mode: 0644]
bin/docx2asn [new file with mode: 0755]

diff --git a/awk/txt2asn-integrated.awk b/awk/txt2asn-integrated.awk
new file mode 100644 (file)
index 0000000..a4f1acf
--- /dev/null
@@ -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<position;i++) {
+               indentation = indentation " ";
+           }
+
+           #print "Il y a " field_description_len[structure[line]][field[line]] " ligne(s)";
+
+           print "";
+
+           if (field_description_len[structure[line]][field[line]] > 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 (file)
index 0000000..0c022e0
--- /dev/null
@@ -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 (executable)
index 0000000..7618cb8
--- /dev/null
@@ -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
+