From 4630eb7a2b0b61a4e9ea3a99e7a8cdaba05392cd Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Thu, 28 Jun 2018 19:03:40 +0200 Subject: Removed the definition of old kinds of variables. --- src/analysis/variable.c | 789 ++---------------------------------------------- src/analysis/variable.h | 169 +---------- 2 files changed, 35 insertions(+), 923 deletions(-) diff --git a/src/analysis/variable.c b/src/analysis/variable.c index 95b7a9c..b983b73 100644 --- a/src/analysis/variable.c +++ b/src/analysis/variable.c @@ -64,6 +64,35 @@ static void g_binary_variable_init(GBinVariable *); +/* -------------------- BASE DE VARIABLES OU VARIABLES INCONNUES -------------------- */ + + +/* Base de variable (instance) */ +struct _GUnknownVariable +{ + GObject parent; /* A laisser en premier */ + + size_t offset; /* Position abstraite associée */ + size_t size; /* Taille en mémoire */ + +}; + +/* Base de variable (classe) */ +struct _GUnknownVariableClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Initialise la classe des bases de variables. */ +static void g_unknown_variable_class_init(GUnknownVariableClass *); + +/* Initialise l'instande d'une base de variable. */ +static void g_unknown_variable_init(GUnknownVariable *); + + + /* ---------------------------------------------------------------------------------- */ /* ASSOCIATION D'UN TYPE ET D'UNE DESIGNATION */ /* ---------------------------------------------------------------------------------- */ @@ -312,64 +341,6 @@ void g_binary_variable_output(const GBinVariable *var, GLangOutput *lang, GBuffe - - - - - - - - - - - -#include -#include -#include - - -#include "../common/extstr.h" - - - - - - - - - - - - -/* -------------------- BASE DE VARIABLES OU VARIABLES INCONNUES -------------------- */ - - -/* Base de variable (instance) */ -struct _GUnknownVariable -{ - GObject parent; /* A laisser en premier */ - - size_t offset; /* Position abstraite associée */ - size_t size; /* Taille en mémoire */ - -}; - -/* Base de variable (classe) */ -struct _GUnknownVariableClass -{ - GObjectClass parent; /* A laisser en premier */ - -}; - - -/* Initialise la classe des bases de variables. */ -static void g_unknown_variable_class_init(GUnknownVariableClass *); - -/* Initialise l'instande d'une base de variable. */ -static void g_unknown_variable_init(GUnknownVariable *); - - - /* ---------------------------------------------------------------------------------- */ /* BASE DE VARIABLES OU VARIABLES INCONNUES */ /* ---------------------------------------------------------------------------------- */ @@ -533,705 +504,3 @@ bool g_unknown_variable_contains_offset(const GUnknownVariable *var, size_t offs return result; } - - - - - - -/* ---------------------------- TYPES DE DONNEES SIMPLES ---------------------------- */ - - -/* Variable représentant un argument ou un type de retour */ -struct _simple_variable -{ - BaseType type; /* Type représenté */ - -}; - - -/* Décrit la variable simple sous forme de caractères. */ -char *simple_var_to_string(const simple_variable *); - -/* Supprime de la mémoire une variable de type simple. */ -void delete_simple_var(simple_variable *); - - - -/* --------------------- ENCAPSULATIONS DES VARIABLES COMPLEXES --------------------- */ - - -/* Supprime de la mémoire une variable de type complexe. */ -typedef void (* delete_complex_fc) (complex_variable *); - -/* Décrit la variable complexe sous forme de caractères. */ -typedef char * (* complex_to_string_fc) (const complex_variable *); - - -/* Représentation d'une variable complexe */ -struct _complex_variable -{ - delete_complex_fc delete; /* Procédure de suppression */ - complex_to_string_fc to_string; /* Conversion en chaîne */ - -}; - - -/* Initialise une représentation de variable complexe. */ -void init_complex_var(complex_variable *); - -/* Supprime de la mémoire une variable de type complexe. */ -void delete_complex_var(complex_variable *); - -/* Décrit la variable simple sous forme de caractères. */ -char *complex_var_to_string(const complex_variable *); - - - -/* ---------------------- VARIABLES DE CLASSES ET ENUMERATIONS ---------------------- */ - - -/* Représentation des classes et des énumérations */ -struct _class_enum_variable -{ - complex_variable complex; /* A laisser en premier */ - - ClassEnumType type; /* Type représenté si connu */ - - char *desc; /* Description humaine */ - -}; - - -/* Supprime de la mémoire une variable de classe/enumération. */ -void delete_class_enum_var(class_enum_variable *); - -/* Décrit la variable complexe sous forme de caractères. */ -char *class_enum_var_to_string(const class_enum_variable *); - - - -/* -------------------------- VARIABLES DEPENDANT D'AUTRES -------------------------- */ - - -/* Représentation des variables dérivées */ -struct _encapsulated_variable -{ - complex_variable complex; /* A laisser en premier */ - - EncapsulationType type; /* Encapsulation utilisée */ - variable *child; /* Sous-type encadré */ - -}; - - -/* Supprime de la mémoire une variable dérivée. */ -void delete_encapsulated_var(encapsulated_variable *); - -/* Décrit la variable dérivée sous forme de caractères. */ -char *encapsulated_var_to_string(const encapsulated_variable *); - - - -/* ---------------------- MANIPULATION GENERIQUE DES VARIABLES ---------------------- */ - - -/* Variable représentant un argument ou un type de retour */ -struct _variable -{ - union - { - simple_variable *simple; /* Variable simple */ - complex_variable *complex; /* Variable plus compliquée */ - - } value; - - bool is_simple; /* Choix du champ valide */ - - VariableQualifier qualifiers; /* Eventuels qualificatifs */ - -}; - - - -/* ---------------------------------------------------------------------------------- */ -/* TYPES DE DONNEES SIMPLES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Crée une représentation de variable. * -* * -* Retour : Adresse de la structure mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -simple_variable *create_simple_var(void) -{ - simple_variable *result; /* Structure à retourner */ - - result = (simple_variable *)calloc(1, sizeof(simple_variable)); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : type = type de base à représenter. * -* * -* Description : Crée une représentation de variable à type connu. * -* * -* Retour : Adresse de la structure mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -simple_variable *create_typed_simple_var(BaseType type) -{ - simple_variable *result; /* Structure à retourner */ - - result = create_simple_var(); - - set_simple_var_type(result, type); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à effacer. * -* * -* Description : Supprime de la mémoire une variable de type simple. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void delete_simple_var(simple_variable *var) -{ - free(var); - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à mettre à jour. * -* type = type de base à représenter. * -* * -* Description : Définit le type d'une variable simple. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void set_simple_var_type(simple_variable *var, BaseType type) -{ - var->type = type; - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à consulter. * -* * -* Description : Décrit la variable simple sous forme de caractères. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -char *simple_var_to_string(const simple_variable *var) -{ - char *result; /* Chaîne à renvoyer */ - - switch (var->type) - { - case BTP_VOID: - result = "void"; - break; - case BTP_WCHAR_T: - result = "wchar_t"; - break; - case BTP_BOOL: - result = "bool"; - break; - case BTP_CHAR: - result = "char"; - break; - case BTP_SCHAR: - result = "signed char"; - break; - case BTP_UCHAR: - result = "unsigned char"; - break; - case BTP_SHORT: - result = "short"; - break; - case BTP_USHORT: - result = "unsigned short"; - break; - case BTP_INT: - result = "int"; - break; - case BTP_UINT: - result = "unsigned int"; - break; - case BTP_LONG: - result = "long"; - break; - case BTP_ULONG: - result = "unsigned long"; - break; - case BTP_LONG_LONG: - result = "long long"; - break; - case BTP_ULONG_LONG: - result = "unsigned long long"; - break; - case BTP_INT128: - result = "__int128"; - break; - case BTP_UINT128: - result = "__uint128"; - break; - case BTP_FLOAT: - result = "float"; - break; - case BTP_DOUBLE: - result = "double"; - break; - case BTP_LONG_DOUBLE: - result = "__float80"; - break; - case BTP_FLOAT128: - result = "__float128"; - break; - case BTP_ELLIPSIS: - result = "..."; - break; - case BTP_754R_64: - result = "754r_float64"; - break; - case BTP_754R_128: - result = "754r_float128"; - break; - case BTP_754R_32: - result = "754r_float32"; - break; - case BTP_754R_16: - result = "754r_float16"; - break; - case BTP_CHAR32_T: - result = "char32_t"; - break; - case BTP_CHAR16_T: - result = "char16_t"; - break; - case BTP_OTHER: - result = "[toto]"; /* FIXME */ - break; - default: - result = "/* pour gcc */"; - break; - } - - result = strdup(result); - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* ENCAPSULATIONS DES VARIABLES COMPLEXES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : var = structure vierge à préparer. * -* * -* Description : Initialise une représentation de variable complexe. * -* * -* Retour : Adresse de la structure mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -void init_complex_var(complex_variable *var) -{ - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à effacer. * -* * -* Description : Supprime de la mémoire une variable de type complexe. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void delete_complex_var(complex_variable *var) -{ - var->delete(var); - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à consulter. * -* * -* Description : Décrit la variable complexe sous forme de caractères. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -char *complex_var_to_string(const complex_variable *var) -{ - return var->to_string(var); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* VARIABLES DE CLASSES ET ENUMERATIONS */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : type = type de base à représenter. * -* desc = description humaine de la variable. * -* * -* Description : Crée une représentation de variable de classe/enumération. * -* * -* Retour : Adresse de la structure mise en place. * -* * -* Remarques : La description ne doit pas être libérée par l'appelant ! * -* * -******************************************************************************/ - -complex_variable *create_class_enum_var(char *desc) -{ - class_enum_variable *result; /* Structure à retourner */ - - result = (class_enum_variable *)calloc(1, sizeof(class_enum_variable)); - - init_complex_var(COMPLEX_VAR(result)); - - COMPLEX_VAR(result)->delete = (delete_complex_fc)delete_class_enum_var; - COMPLEX_VAR(result)->to_string = (complex_to_string_fc)class_enum_var_to_string; - - result->desc = desc; - - return COMPLEX_VAR(result); - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à effacer. * -* * -* Description : Supprime de la mémoire une variable de classe/enumération. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void delete_class_enum_var(class_enum_variable *var) -{ - free(var->desc); - - free(var); - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à consulter. * -* * -* Description : Décrit la variable complexe sous forme de caractères. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -char *class_enum_var_to_string(const class_enum_variable *var) -{ - return strdup(var->desc); - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* VARIABLES DEPENDANT D'AUTRES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : type = type d'extension à représenter. * -* child = variable dont on doit dériver. * -* * -* Description : Crée une représentation de variable dérivée. * -* * -* Retour : Adresse de la structure mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -complex_variable *create_encapsulated_var(EncapsulationType type, variable *child) -{ - encapsulated_variable *result; /* Structure à retourner */ - - result = (encapsulated_variable *)calloc(1, sizeof(encapsulated_variable)); - - init_complex_var(COMPLEX_VAR(result)); - - COMPLEX_VAR(result)->delete = (delete_complex_fc)delete_encapsulated_var; - COMPLEX_VAR(result)->to_string = (complex_to_string_fc)encapsulated_var_to_string; - - result->type = type; - result->child = child; - - return COMPLEX_VAR(result); - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à effacer. * -* * -* Description : Supprime de la mémoire une variable dérivée. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void delete_encapsulated_var(encapsulated_variable *var) -{ - delete_var(var->child); - - free(var); - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à consulter. * -* * -* Description : Décrit la variable dérivée sous forme de caractères. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -char *encapsulated_var_to_string(const encapsulated_variable *var) -{ - char *result; /* Chaîne finale à renvoyer */ - - result = var_to_string(var->child); - - switch (var->type) - { - case ECT_POINTER: - if (result[strlen(result) - 1] == '*') result = stradd(result, "*"); - else result = stradd(result, " *"); - break; - case ECT_REFERENCE: - result = stradd(result, " &"); - break; - case ECT_RVALUE_REF: - result = stradd(result, " [[rval ???]]") /* FIXME */; - break; - case ECT_COMPLEX: - result = stradd(result, " complex"); - break; - case ECT_IMAGINARY: - result = stradd(result, " imaginary"); - break; - case ECT_ROUTINE: - result = stradd(result, "< routine ? TODO ! >"); - break; - } - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* MANIPULATION GENERIQUE DES VARIABLES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : var = variable à emballer. * -* * -* Description : Crée une représentation de variable (simple). * -* * -* Retour : Adresse de la structure mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -variable *create_var_from_simple_one(simple_variable *var) -{ - variable *result; /* Structure à retourner */ - - result = (variable *)calloc(1, sizeof(variable)); - - result->value.simple = var; - result->is_simple = true; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à emballer. * -* * -* Description : Crée une représentation de variable (complexe). * -* * -* Retour : Adresse de la structure mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -variable *create_var_from_complex_one(complex_variable *var) -{ - variable *result; /* Structure à retourner */ - - result = (variable *)calloc(1, sizeof(variable)); - - result->value.complex = var; - result->is_simple = false; - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à effecer. * -* * -* Description : Supprime la représentation de variable de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void delete_var(variable *var) -{ - if (var->is_simple) delete_simple_var(var->value.simple); - else delete_complex_var(var->value.complex); - - free(var); - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à mettre à jour. * -* qualifier = nouveau qualificatif pour la variable. * -* * -* Description : Ajoute un qualificatif à la variable. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void add_qualifier_to_var(variable *var, VariableQualifier qualifier) -{ - var->qualifiers |= qualifier; - -} - - -/****************************************************************************** -* * -* Paramètres : var = variable à consulter. * -* * -* Description : Décrit la variable sous forme de caractères. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -char *var_to_string(const variable *var) -{ - char *result; /* Chaîne à renvoyer */ - - if (var->is_simple) result = simple_var_to_string(var->value.simple); - else result = complex_var_to_string(var->value.complex); - - if (var->qualifiers & VQF_RESTRICT) - strprep(result, "restrict "); - - if (var->qualifiers & VQF_VOLATILE) - strprep(result, "volatile "); - - if (var->qualifiers & VQF_CONST) - strprep(result, "const "); - - return result; - -} diff --git a/src/analysis/variable.h b/src/analysis/variable.h index bc284ae..94ac432 100644 --- a/src/analysis/variable.h +++ b/src/analysis/variable.h @@ -81,18 +81,15 @@ char *g_binary_variable_to_string(const GBinVariable *, bool); - - - /* -------------------- BASE DE VARIABLES OU VARIABLES INCONNUES -------------------- */ -#define G_TYPE_UNKNOWN_VARIABLE g_unknown_variable_get_type() -#define G_UNKNOWN_VARIABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_unknown_variable_get_type(), GUnknownVariable)) -#define G_IS_UNKNOWN_VARIABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_unknown_variable_get_type())) -#define G_UNKNOWN_VARIABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_UNKNOWN_VARIABLE, GUnknownVariableClass)) -#define G_IS_UNKNOWN_VARIABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_UNKNOWN_VARIABLE)) -#define G_UNKNOWN_VARIABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_UNKNOWN_VARIABLE, GUnknownVariableClass)) +#define G_TYPE_UNKNOWN_VARIABLE g_unknown_variable_get_type() +#define G_UNKNOWN_VARIABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_UNKNOWN_VARIABLE, GUnknownVariable)) +#define G_IS_UNKNOWN_VARIABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_UNKNOWN_VARIABLE)) +#define G_UNKNOWN_VARIABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_UNKNOWN_VARIABLE, GUnknownVariableClass)) +#define G_IS_UNKNOWN_VARIABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_UNKNOWN_VARIABLE)) +#define G_UNKNOWN_VARIABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_UNKNOWN_VARIABLE, GUnknownVariableClass)) /* Base de variable (instance) */ @@ -122,158 +119,4 @@ bool g_unknown_variable_contains_offset(const GUnknownVariable *, size_t); - - -/* Variable repésentant un argument ou un type de retour */ -typedef struct _variable variable; - - - -/* ---------------------------- TYPES DE DONNEES SIMPLES ---------------------------- */ - - -/* Liste des types de base existants */ -#if 0 -typedef enum _BaseType -{ - BTP_VOID, /* void */ - BTP_WCHAR_T, /* wchar_t */ - BTP_BOOL, /* bool */ - BTP_CHAR, /* char */ - BTP_SCHAR, /* signed char */ - BTP_UCHAR, /* unsigned char */ - BTP_SHORT, /* short */ - BTP_USHORT, /* unsigned short */ - BTP_INT, /* int */ - BTP_UINT, /* unsigned int */ - BTP_LONG, /* long */ - BTP_ULONG, /* unsigned long */ - BTP_LONG_LONG, /* long long, __int64 */ - BTP_ULONG_LONG, /* unsigned long long, __int64 */ - BTP_INT128, /* __int128 */ - BTP_UINT128, /* unsigned __int128 */ - BTP_FLOAT, /* float */ - BTP_DOUBLE, /* double */ - BTP_LONG_DOUBLE, /* long double, __float80 */ - BTP_FLOAT128, /* __float128 */ - BTP_ELLIPSIS, /* ... */ - BTP_754R_64, /* IEEE 754r float (64 bits) */ - BTP_754R_128, /* IEEE 754r float (128 bits) */ - BTP_754R_32, /* IEEE 754r float (32 bits) */ - BTP_754R_16, /* IEEE 754r float (16 bits) */ - BTP_CHAR32_T, /* char32_t */ - BTP_CHAR16_T, /* char16_t */ - BTP_OTHER /* Extension utilisateur */ - -} BaseType; -#endif - - -/* Variable repésentant un argument ou un type de retour */ -typedef struct _simple_variable simple_variable; - - -/* Crée une représentation de variable. */ -simple_variable *create_simple_var(void); - -/* Crée une représentation de variable à type connu. */ -simple_variable *create_typed_simple_var(BaseType); - -/* Définit le type d'une variable simple. */ -void set_simple_var_type(simple_variable *, BaseType); - - - -/* --------------------- ENCAPSULATIONS DES VARIABLES COMPLEXES --------------------- */ - - -/* Représentation d'une variable complexe */ -typedef struct _complex_variable complex_variable; - - -#define COMPLEX_VAR(v) ((complex_variable *)v) - - - -/* ---------------------- VARIABLES DE CLASSES ET ENUMERATIONS ---------------------- */ - - -/* Type de ces variables */ -#if 0 -typedef enum _ClassEnumType -{ - CET_UNKNOWN, /* Statut inconnu */ - CET_STRUCT, /* Structure */ - CET_ENUM, /* Enumération */ - CET_CLASS /* Classe */ - -} ClassEnumType; -#endif - - -/* Représentation des classes et des énumérations */ -typedef struct _class_enum_variable class_enum_variable; - - -/* Crée une représentation de variable de classe/enumération. */ -complex_variable *create_class_enum_var(char *); - - - -/* -------------------------- VARIABLES DEPENDANT D'AUTRES -------------------------- */ - - -/* Cas d'encapsulation possibles */ -#if 0 -typedef enum _EncapsulationType -{ - ECT_POINTER, /* Pointeur */ - ECT_REFERENCE, /* Référence */ - ECT_RVALUE_REF, /* Référence ?? (C++0x) */ - ECT_COMPLEX, /* Complexe (C 2000) */ - ECT_IMAGINARY /* Imaginaire (C 2000) */ - -} EncapsulationType; -#endif - - -/* Représentation des variables dérivées */ -typedef struct _encapsulated_variable encapsulated_variable; - - -/* Crée une représentation de variable dérivée. */ -complex_variable *create_encapsulated_var(EncapsulationType, variable *); - - - -/* ---------------------- MANIPULATION GENERIQUE DES VARIABLES ---------------------- */ - - -/* Qualificatifs de variables */ -typedef enum _VariableQualifier -{ - VQF_RESTRICT = (1 << 0), /* restrict (C99) */ - VQF_VOLATILE = (1 << 1), /* volatile */ - VQF_CONST = (1 << 2) /* const */ - -} VariableQualifier; - - -/* Crée une représentation de variable (simple). */ -variable *create_var_from_simple_one(simple_variable *); - -/* Crée une représentation de variable (complexe). */ -variable *create_var_from_complex_one(complex_variable *); - -/* Supprime la représentation de variable de la mémoire. */ -void delete_var(variable *); - -/* Ajoute un qualificatif à la variable. */ -void add_qualifier_to_var(variable *, VariableQualifier); - -/* Décrit la variable sous forme de caractères. */ -char *var_to_string(const variable *); - - - #endif /* _ANALYSIS_VARIABLE_H */ -- cgit v0.11.2-87-g4458