kopia lustrzana https://github.com/weetmuts/wmbusmeters
				
				
				
			Add fractions to force_scale = 1/3
							rodzic
							
								
									d7c6058c14
								
							
						
					
					
						commit
						2b97ac189d
					
				| 
						 | 
				
			
			@ -9,33 +9,26 @@ driver {
 | 
			
		|||
        mvt = SEN,7c,07
 | 
			
		||||
    }
 | 
			
		||||
    field {
 | 
			
		||||
        name        = total
 | 
			
		||||
        quantity    = Volume
 | 
			
		||||
        name     = total
 | 
			
		||||
        quantity = Volume
 | 
			
		||||
        info     = 'The total water consumption.'
 | 
			
		||||
        match {
 | 
			
		||||
            measurement_type = Instantaneous
 | 
			
		||||
            vif_range        = Volume
 | 
			
		||||
        }
 | 
			
		||||
        about {
 | 
			
		||||
            de = 'Der Gesamtwasserverbrauch.'
 | 
			
		||||
            en = 'The total water consumption.'
 | 
			
		||||
            fr = '''La consommation totale d'eau.'''
 | 
			
		||||
            sv = 'Den totala vattenförbrukningen.'
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    field {
 | 
			
		||||
        name        = max_flow
 | 
			
		||||
        quantity    = Flow
 | 
			
		||||
        name     = max_flow
 | 
			
		||||
        quantity = Flow
 | 
			
		||||
        info     = 'The maximum water flow recorded during previous period.'
 | 
			
		||||
        match {
 | 
			
		||||
            measurement_type = Instantaneous
 | 
			
		||||
            vif_range        = VolumeFlow
 | 
			
		||||
        }
 | 
			
		||||
        about {
 | 
			
		||||
              en = 'The maximum flow recorded during previous period.'
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    test {
 | 
			
		||||
        args = 'MoreWater iperl 12345699 NOKEY'
 | 
			
		||||
        coment = 'Test iPerl T1 telegram, that after decryption, has 2f2f markers.'
 | 
			
		||||
        comment = 'Test iPerl T1 telegram, that after decryption, has 2f2f markers.'
 | 
			
		||||
        telegram = 1E44AE4C9956341268077A36001000_2F2F0413181E0000023B00002F2F2F2F
 | 
			
		||||
        json = '{"media":"water","meter":"iperl","name":"MoreWater","id":"12345699","total_m3":7.704,"max_flow_m3h":0,"timestamp":"1111-11-11T11:11:11Z"}'
 | 
			
		||||
        fields = 'MoreWater;12345699;7.704;0;1111-11-11 11:11.11'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ PrintProperties check_print_properties(const char *print_properties_s, DriverDyn
 | 
			
		|||
string get_translation(XMQDoc *doc, XMQNode *node, string name, string lang);
 | 
			
		||||
string check_calculate(const char *formula, DriverDynamic *dd);
 | 
			
		||||
Unit check_display_unit(const char *display_unit, DriverDynamic *dd);
 | 
			
		||||
double check_force_scale(double force_scale, DriverDynamic *dd);
 | 
			
		||||
double check_force_scale(const char *force_scale, DriverDynamic *dd);
 | 
			
		||||
 | 
			
		||||
bool checked_set_difvifkey(const char *difvifkey_s, FieldMatcher *fm, DriverDynamic *dd);
 | 
			
		||||
void checked_set_measurement_type(const char *measurement_type_s, FieldMatcher *fm, DriverDynamic *dd);
 | 
			
		||||
| 
						 | 
				
			
			@ -286,8 +286,9 @@ XMQProceed DriverDynamic::add_field(XMQDoc *doc, XMQNode *field, DriverDynamic *
 | 
			
		|||
    // The display unit is usually based on the quantity. But you can override it.
 | 
			
		||||
    Unit display_unit = check_display_unit(xmqGetStringRel(doc, "display_unit", field), dd);
 | 
			
		||||
 | 
			
		||||
    // A field can force a scale factor. Defaults to 1.0
 | 
			
		||||
    double force_scale = check_force_scale(xmqGetDoubleRel(doc, "force_scale", field), dd);
 | 
			
		||||
    // A field can force a scale factor. Defaults to 1.0 but you can override
 | 
			
		||||
    // with 1.123 or 1/32 or 0.33333 or 3.14/2.5
 | 
			
		||||
    double force_scale = check_force_scale(xmqGetStringRel(doc, "force_scale", field), dd);
 | 
			
		||||
 | 
			
		||||
    // Now find all matchers.
 | 
			
		||||
    FieldMatcher match = FieldMatcher::build();
 | 
			
		||||
| 
						 | 
				
			
			@ -752,12 +753,71 @@ Unit check_display_unit(const char *display_unit_s, DriverDynamic *dd)
 | 
			
		|||
    return u;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double check_force_scale(double force_scale, DriverDynamic *dd)
 | 
			
		||||
double check_force_scale(const char *force_scale, DriverDynamic *dd)
 | 
			
		||||
{
 | 
			
		||||
    // TODO improve error detection.
 | 
			
		||||
    if (force_scale == 0) return 1.0;
 | 
			
		||||
 | 
			
		||||
    return force_scale;
 | 
			
		||||
    const char *start = force_scale;
 | 
			
		||||
    const char *stop = force_scale+strlen(force_scale);
 | 
			
		||||
    while (start < stop && (*start == ' ' || *start == '\n')) start++;
 | 
			
		||||
    while (start < stop && (*stop == ' ' || *stop == '\n')) stop--;
 | 
			
		||||
 | 
			
		||||
    const char *slash = strchr(force_scale, '/');
 | 
			
		||||
    if (slash == NULL)
 | 
			
		||||
    {
 | 
			
		||||
        char *end;
 | 
			
		||||
        double d = strtod(start, &end);
 | 
			
		||||
        if (end != stop)
 | 
			
		||||
        {
 | 
			
		||||
            warning("(driver) error in %s, unparseable force_scale: %s\n"
 | 
			
		||||
                    "You can force scales such as:\n"
 | 
			
		||||
                    "3.14\n"
 | 
			
		||||
                    "2/3\n"
 | 
			
		||||
                    "12.5\n"
 | 
			
		||||
                    "12.5/5.3\n",
 | 
			
		||||
                    dd->fileName().c_str(),
 | 
			
		||||
                    force_scale);
 | 
			
		||||
            throw 1;
 | 
			
		||||
        }
 | 
			
		||||
        return d;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const char *numerator_stop = slash;
 | 
			
		||||
    const char *denominator_start = slash+1;
 | 
			
		||||
    while (start < numerator_stop && (*numerator_stop == ' ' || *numerator_stop == '\n')) numerator_stop--;
 | 
			
		||||
    while (denominator_start < stop && (*denominator_start == ' ' || *denominator_start == '\n')) denominator_start++;
 | 
			
		||||
 | 
			
		||||
    char *end;
 | 
			
		||||
    double num = strtod(start, &end);
 | 
			
		||||
    if (end != numerator_stop)
 | 
			
		||||
    {
 | 
			
		||||
        warning("(driver) error in %s, unparseable numerator in force_scale: %s\n"
 | 
			
		||||
                "You can force scales such as:\n"
 | 
			
		||||
                "3.14\n"
 | 
			
		||||
                "2/3\n"
 | 
			
		||||
                "12.5\n"
 | 
			
		||||
                "12.5/5.3\n",
 | 
			
		||||
                dd->fileName().c_str(),
 | 
			
		||||
                force_scale);
 | 
			
		||||
        throw 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    double denom = strtod(denominator_start, &end);
 | 
			
		||||
    if (end != stop)
 | 
			
		||||
    {
 | 
			
		||||
        warning("(driver) error in %s, unparseable denominator in force_scale: %s\n"
 | 
			
		||||
                "You can force scales such as:\n"
 | 
			
		||||
                "3.14\n"
 | 
			
		||||
                "2/3\n"
 | 
			
		||||
                "12.5\n"
 | 
			
		||||
                "12.5/5.3\n",
 | 
			
		||||
                dd->fileName().c_str(),
 | 
			
		||||
                force_scale);
 | 
			
		||||
        throw 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    double d = num / denom;
 | 
			
		||||
    return d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool checked_set_difvifkey(const char *difvifkey_s, FieldMatcher *fm, DriverDynamic *dd)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										305
									
								
								src/xmq.c
								
								
								
								
							
							
						
						
									
										305
									
								
								src/xmq.c
								
								
								
								
							| 
						 | 
				
			
			@ -452,7 +452,9 @@ struct XMQParseState
 | 
			
		|||
    Stack *element_stack; // Top is last created node
 | 
			
		||||
    void *element_last; // Last added sibling to stack top node.
 | 
			
		||||
    bool parsing_doctype; // True when parsing a doctype.
 | 
			
		||||
    void *add_doctype_before; // Used when retrofitting a doctype found in json.
 | 
			
		||||
    void *add_pre_node_before; // Used when retrofitting pre-root comments and doctype found in json.
 | 
			
		||||
    bool root_found; // Used to decide if _// should be printed before or after root.
 | 
			
		||||
    void *add_post_node_after; // Used when retrofitting post-root comments found in json.
 | 
			
		||||
    bool doctype_found; // True after a doctype has been parsed.
 | 
			
		||||
    bool parsing_pi; // True when parsing a processing instruction, pi.
 | 
			
		||||
    bool merge_text; // Merge text nodes and character entities.
 | 
			
		||||
| 
						 | 
				
			
			@ -511,7 +513,10 @@ struct XMQPrintState
 | 
			
		|||
    const char *replay_active_color_pre;
 | 
			
		||||
    const char *restart_line;
 | 
			
		||||
    const char *last_namespace;
 | 
			
		||||
    xmlNode *doctype; // Used to remember doctype when printing json.
 | 
			
		||||
    Stack *pre_nodes; // Used to remember leading comments/doctype when printing json.
 | 
			
		||||
    size_t pre_post_num_comments_total; // Number of comments outside of the root element.
 | 
			
		||||
    size_t pre_post_num_comments_used; // Active number of comment outside of the root element.
 | 
			
		||||
    Stack *post_nodes; // Used to remember ending comments when printing json.
 | 
			
		||||
    XMQOutputSettings *output_settings;
 | 
			
		||||
    XMQDoc *doq;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -877,8 +882,10 @@ typedef struct Stack Stack;
 | 
			
		|||
Stack *new_stack();
 | 
			
		||||
void free_stack(Stack *stack);
 | 
			
		||||
void push_stack(Stack *s, void *);
 | 
			
		||||
size_t size_stack();
 | 
			
		||||
// Pop the top element.
 | 
			
		||||
void *pop_stack(Stack *s);
 | 
			
		||||
// Pull the bottom element.
 | 
			
		||||
void *rock_stack(Stack *s);
 | 
			
		||||
 | 
			
		||||
#define STACK_MODULE
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1237,7 +1244,9 @@ struct XMQParseState
 | 
			
		|||
    Stack *element_stack; // Top is last created node
 | 
			
		||||
    void *element_last; // Last added sibling to stack top node.
 | 
			
		||||
    bool parsing_doctype; // True when parsing a doctype.
 | 
			
		||||
    void *add_doctype_before; // Used when retrofitting a doctype found in json.
 | 
			
		||||
    void *add_pre_node_before; // Used when retrofitting pre-root comments and doctype found in json.
 | 
			
		||||
    bool root_found; // Used to decide if _// should be printed before or after root.
 | 
			
		||||
    void *add_post_node_after; // Used when retrofitting post-root comments found in json.
 | 
			
		||||
    bool doctype_found; // True after a doctype has been parsed.
 | 
			
		||||
    bool parsing_pi; // True when parsing a processing instruction, pi.
 | 
			
		||||
    bool merge_text; // Merge text nodes and character entities.
 | 
			
		||||
| 
						 | 
				
			
			@ -1296,7 +1305,10 @@ struct XMQPrintState
 | 
			
		|||
    const char *replay_active_color_pre;
 | 
			
		||||
    const char *restart_line;
 | 
			
		||||
    const char *last_namespace;
 | 
			
		||||
    xmlNode *doctype; // Used to remember doctype when printing json.
 | 
			
		||||
    Stack *pre_nodes; // Used to remember leading comments/doctype when printing json.
 | 
			
		||||
    size_t pre_post_num_comments_total; // Number of comments outside of the root element.
 | 
			
		||||
    size_t pre_post_num_comments_used; // Active number of comment outside of the root element.
 | 
			
		||||
    Stack *post_nodes; // Used to remember ending comments when printing json.
 | 
			
		||||
    XMQOutputSettings *output_settings;
 | 
			
		||||
    XMQDoc *doq;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1578,6 +1590,7 @@ typedef struct XMQPrintState XMQPrintState;
 | 
			
		|||
 | 
			
		||||
void xmq_fixup_json_before_writeout(XMQDoc *doq);
 | 
			
		||||
void json_print_object_nodes(XMQPrintState *ps, xmlNode *container, xmlNode *from, xmlNode *to);
 | 
			
		||||
void collect_leading_ending_comments_doctype(XMQPrintState *ps, xmlNodePtr *first, xmlNodePtr *last);
 | 
			
		||||
void json_print_array_nodes(XMQPrintState *ps, xmlNode *container, xmlNode *from, xmlNode *to);
 | 
			
		||||
bool xmq_tokenize_buffer_json(XMQParseState *state, const char *start, const char *stop);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2103,6 +2116,10 @@ void setup_tex_coloring(XMQOutputSettings *os, XMQTheme *theme, bool dark_mode,
 | 
			
		|||
    theme->attr_value_compound_quote.post = "}";
 | 
			
		||||
    theme->attr_value_compound_entity.pre = "\\xmqE{";
 | 
			
		||||
    theme->attr_value_compound_entity.post = "}";
 | 
			
		||||
    theme->ns_declaration.pre = "\\xmqNSD{";
 | 
			
		||||
    theme->ns_declaration.post = "}";
 | 
			
		||||
    theme->ns_override_xsl.pre = "\\xmqXSL{";
 | 
			
		||||
    theme->ns_override_xsl.post = "}";
 | 
			
		||||
    theme->ns_colon.pre = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3503,7 +3520,21 @@ void do_comment(XMQParseState*state,
 | 
			
		|||
    size_t indent = col-1;
 | 
			
		||||
    char *trimmed = (state->no_trim_quotes)?strndup(start, stop-start):xmq_un_comment(indent, ' ', start, stop);
 | 
			
		||||
    xmlNodePtr n = xmlNewDocComment(state->doq->docptr_.xml, (const xmlChar *)trimmed);
 | 
			
		||||
    xmlAddChild(parent, n);
 | 
			
		||||
 | 
			
		||||
    if (state->add_pre_node_before)
 | 
			
		||||
    {
 | 
			
		||||
        // Insert comment before this node.
 | 
			
		||||
        xmlAddPrevSibling((xmlNodePtr)state->add_pre_node_before, n);
 | 
			
		||||
    }
 | 
			
		||||
    else if (state->add_post_node_after)
 | 
			
		||||
    {
 | 
			
		||||
        // Insert comment after this node.
 | 
			
		||||
        xmlAddNextSibling((xmlNodePtr)state->add_post_node_after, n);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        xmlAddChild(parent, n);
 | 
			
		||||
    }
 | 
			
		||||
    state->element_last = n;
 | 
			
		||||
    free(trimmed);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -3613,10 +3644,10 @@ void do_element_value_quote(XMQParseState *state,
 | 
			
		|||
            longjmp(state->error_handler, 1);
 | 
			
		||||
        }
 | 
			
		||||
        state->doq->docptr_.xml->intSubset = dtd;
 | 
			
		||||
        if (state->add_doctype_before)
 | 
			
		||||
        if (state->add_pre_node_before)
 | 
			
		||||
        {
 | 
			
		||||
            // Insert doctype before this node.
 | 
			
		||||
            xmlAddPrevSibling((xmlNodePtr)state->add_doctype_before, (xmlNodePtr)dtd);
 | 
			
		||||
            xmlAddPrevSibling((xmlNodePtr)state->add_pre_node_before, (xmlNodePtr)dtd);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -4167,6 +4198,8 @@ void xmq_print_json(XMQDoc *doq, XMQOutputSettings *os)
 | 
			
		|||
    void *last = doq->docptr_.xml->last;
 | 
			
		||||
 | 
			
		||||
    XMQPrintState ps = {};
 | 
			
		||||
    ps.pre_nodes = new_stack();
 | 
			
		||||
    ps.post_nodes = new_stack();
 | 
			
		||||
    XMQWrite write = os->content.write;
 | 
			
		||||
    void *writer_state = os->content.writer_state;
 | 
			
		||||
    ps.doq = doq;
 | 
			
		||||
| 
						 | 
				
			
			@ -4174,8 +4207,14 @@ void xmq_print_json(XMQDoc *doq, XMQOutputSettings *os)
 | 
			
		|||
    ps.output_settings = os;
 | 
			
		||||
    assert(os->content.write);
 | 
			
		||||
 | 
			
		||||
    // Find any leading (doctype/comments) and ending (comments) nodes and store in pre_nodes and post_nodes inside ps.
 | 
			
		||||
    // Adjust the first and last pointer.
 | 
			
		||||
    collect_leading_ending_comments_doctype(&ps, (xmlNode**)&first, (xmlNode**)&last);
 | 
			
		||||
    json_print_object_nodes(&ps, NULL, (xmlNode*)first, (xmlNode*)last);
 | 
			
		||||
    write(writer_state, "\n", NULL);
 | 
			
		||||
 | 
			
		||||
    free_stack(ps.pre_nodes);
 | 
			
		||||
    free_stack(ps.post_nodes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void text_print_node(XMQPrintState *ps, xmlNode *node)
 | 
			
		||||
| 
						 | 
				
			
			@ -6342,6 +6381,8 @@ void hashmap_free_iterator(HashMapIterator *i)
 | 
			
		|||
 | 
			
		||||
#ifdef STACK_MODULE
 | 
			
		||||
 | 
			
		||||
StackElement *find_element_above(Stack *s, StackElement *b);
 | 
			
		||||
 | 
			
		||||
Stack *new_stack()
 | 
			
		||||
{
 | 
			
		||||
    Stack *s = (Stack*)malloc(sizeof(Stack));
 | 
			
		||||
| 
						 | 
				
			
			@ -6395,6 +6436,41 @@ void *pop_stack(Stack *stack)
 | 
			
		|||
    return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
StackElement *find_element_above(Stack *s, StackElement *b)
 | 
			
		||||
{
 | 
			
		||||
    StackElement *e = s->top;
 | 
			
		||||
 | 
			
		||||
    for (;;)
 | 
			
		||||
    {
 | 
			
		||||
        if (!e) return NULL;
 | 
			
		||||
        if (e->below == b) return e;
 | 
			
		||||
        e = e->below;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *rock_stack(Stack *stack)
 | 
			
		||||
{
 | 
			
		||||
    assert(stack);
 | 
			
		||||
    assert(stack->bottom);
 | 
			
		||||
 | 
			
		||||
    assert(stack->size > 0);
 | 
			
		||||
 | 
			
		||||
    if (stack->size == 1) return pop_stack(stack);
 | 
			
		||||
 | 
			
		||||
    StackElement *element = stack->bottom;
 | 
			
		||||
    void *data = element->data;
 | 
			
		||||
    StackElement *above = find_element_above(stack, element);
 | 
			
		||||
    assert(above);
 | 
			
		||||
    stack->bottom = above;
 | 
			
		||||
    above->below = NULL;
 | 
			
		||||
    free(element);
 | 
			
		||||
    stack->size--;
 | 
			
		||||
 | 
			
		||||
    return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // STACK_MODULE
 | 
			
		||||
 | 
			
		||||
// PARTS MEMBUFFER_C ////////////////////////////////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -6582,7 +6658,8 @@ void json_print_attributes(XMQPrintState *ps, xmlNodePtr node);
 | 
			
		|||
void json_print_array_with_children(XMQPrintState *ps,
 | 
			
		||||
                                    xmlNode *container,
 | 
			
		||||
                                    xmlNode *node);
 | 
			
		||||
void json_print_comment_node(XMQPrintState *ps, xmlNodePtr node);
 | 
			
		||||
void json_print_comment_node(XMQPrintState *ps, xmlNodePtr node, bool prefix_ul, size_t total, size_t used);
 | 
			
		||||
void json_print_doctype_node(XMQPrintState *ps, xmlNodePtr node);
 | 
			
		||||
void json_print_entity_node(XMQPrintState *ps, xmlNodePtr node);
 | 
			
		||||
void json_print_standalone_quote(XMQPrintState *ps, xmlNode *container, xmlNodePtr node, size_t total, size_t used);
 | 
			
		||||
void json_print_object_nodes(XMQPrintState *ps, xmlNode *container, xmlNode *from, xmlNode *to);
 | 
			
		||||
| 
						 | 
				
			
			@ -6756,7 +6833,7 @@ void parse_json_quote(XMQParseState *state, const char *key_start, const char *k
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (key_start && *key_start == '/' && *(key_start+1) == '/' && key_stop == key_start+2)
 | 
			
		||||
    if (key_start && key_stop == key_start+2 && *key_start == '/' && *(key_start+1) == '/')
 | 
			
		||||
    {
 | 
			
		||||
        // This is "//":"symbol" which means a comment node in xml.
 | 
			
		||||
        DO_CALLBACK_SIM(comment, state, start_line, start_col, content_start, content_stop, content_stop);
 | 
			
		||||
| 
						 | 
				
			
			@ -6764,12 +6841,24 @@ void parse_json_quote(XMQParseState *state, const char *key_start, const char *k
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (key_start && *key_start == '_' && key_stop == key_start+1)
 | 
			
		||||
    if (key_start && key_stop == key_start+3 && *key_start == '_' && *(key_start+1) == '/' && *(key_start+2) == '/')
 | 
			
		||||
    {
 | 
			
		||||
        // This is "_//":"symbol" which means a comment node in xml prefixing the root xml node.
 | 
			
		||||
        if (!state->root_found) state->add_pre_node_before = (xmlNode*)state->element_stack->top->data;
 | 
			
		||||
        else                    state->add_post_node_after = (xmlNode*)state->element_stack->top->data;
 | 
			
		||||
        DO_CALLBACK_SIM(comment, state, start_line, start_col, content_start, content_stop, content_stop);
 | 
			
		||||
        if (!state->root_found) state->add_pre_node_before = NULL;
 | 
			
		||||
        else                    state->add_post_node_after = NULL;
 | 
			
		||||
        free(content_start);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (key_start && key_stop == key_start+1 && *key_start == '_' )
 | 
			
		||||
    {
 | 
			
		||||
        // This is the element name "_":"symbol" stored inside the json object,
 | 
			
		||||
        // in situations where the name is not visible as a key. For example
 | 
			
		||||
        // the root json object and any object in arrays.
 | 
			
		||||
        xmlNodePtr container = (xmlNodePtr)state->element_last;
 | 
			
		||||
        xmlNodePtr container = (xmlNodePtr)state->element_stack->top->data;
 | 
			
		||||
        size_t len = content_stop - content_start;
 | 
			
		||||
        char *name = (char*)malloc(len+1);
 | 
			
		||||
        memcpy(name, content_start, len);
 | 
			
		||||
| 
						 | 
				
			
			@ -6777,6 +6866,8 @@ void parse_json_quote(XMQParseState *state, const char *key_start, const char *k
 | 
			
		|||
        xmlNodeSetName(container, (xmlChar*)name);
 | 
			
		||||
        free(name);
 | 
			
		||||
        free(content_start);
 | 
			
		||||
        // This will be set many times.
 | 
			
		||||
        state->root_found = true;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -6788,9 +6879,10 @@ void parse_json_quote(XMQParseState *state, const char *key_start, const char *k
 | 
			
		|||
            // This is the one and only !DOCTYPE element.
 | 
			
		||||
            DO_CALLBACK_SIM(element_key, state, state->line, state->col, key_start, key_stop, key_stop);
 | 
			
		||||
            state->parsing_doctype = true;
 | 
			
		||||
            state->add_doctype_before = (xmlNode*)state->element_stack->top->data;
 | 
			
		||||
            state->add_pre_node_before = (xmlNode*)state->element_stack->top->data;
 | 
			
		||||
            DO_CALLBACK_SIM(element_value_quote, state, state->line, state->col, content_start, content_stop, content_stop);
 | 
			
		||||
            state->add_doctype_before = NULL;
 | 
			
		||||
            state->add_pre_node_before = NULL;
 | 
			
		||||
            free(content_start);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -7274,21 +7366,19 @@ void json_print_object_nodes(XMQPrintState *ps, xmlNode *container, xmlNode *fro
 | 
			
		|||
 | 
			
		||||
    while (i)
 | 
			
		||||
    {
 | 
			
		||||
        if (!is_doctype_node(i))
 | 
			
		||||
        const char *name = (const char*)i->name;
 | 
			
		||||
        if (name && strcmp(name, "_")) // We have a name and it is NOT a single _
 | 
			
		||||
        {
 | 
			
		||||
            const char *name = (const char*)i->name;
 | 
			
		||||
            if (name && strcmp(name, "_"))
 | 
			
		||||
            Counter *c = (Counter*)hashmap_get(map, name);
 | 
			
		||||
            if (!c)
 | 
			
		||||
            {
 | 
			
		||||
                Counter *c = (Counter*)hashmap_get(map, name);
 | 
			
		||||
                if (!c)
 | 
			
		||||
                {
 | 
			
		||||
                    c = (Counter*)malloc(sizeof(Counter));
 | 
			
		||||
                    memset(c, 0, sizeof(Counter));
 | 
			
		||||
                    hashmap_put(map, name, c);
 | 
			
		||||
                }
 | 
			
		||||
                c->total++;
 | 
			
		||||
                c = (Counter*)malloc(sizeof(Counter));
 | 
			
		||||
                memset(c, 0, sizeof(Counter));
 | 
			
		||||
                hashmap_put(map, name, c);
 | 
			
		||||
            }
 | 
			
		||||
            c->total++;
 | 
			
		||||
        }
 | 
			
		||||
        if (i == to) break;
 | 
			
		||||
        i = xml_next_sibling(i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7306,6 +7396,7 @@ void json_print_object_nodes(XMQPrintState *ps, xmlNode *container, xmlNode *fro
 | 
			
		|||
        {
 | 
			
		||||
            json_print_node(ps, container, i, 1, 0);
 | 
			
		||||
        }
 | 
			
		||||
        if (i == to) break;
 | 
			
		||||
        i = xml_next_sibling(i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7351,6 +7442,13 @@ bool has_attr_other_than_AS_(xmlNode *node)
 | 
			
		|||
 | 
			
		||||
void json_print_node(XMQPrintState *ps, xmlNode *container, xmlNode *node, size_t total, size_t used)
 | 
			
		||||
{
 | 
			
		||||
    // This is a comment translated into "//":"Comment text"
 | 
			
		||||
    if (is_comment_node(node))
 | 
			
		||||
    {
 | 
			
		||||
        json_print_comment_node(ps, node, false, total, used);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Standalone quote must be quoted: 'word' 'some words'
 | 
			
		||||
    if (is_content_node(node))
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -7365,23 +7463,9 @@ void json_print_node(XMQPrintState *ps, xmlNode *container, xmlNode *node, size_
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // This is a comment translated into "_//":"Comment text"
 | 
			
		||||
    if (is_comment_node(node))
 | 
			
		||||
    {
 | 
			
		||||
        json_print_comment_node(ps, node);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // This is doctype node.
 | 
			
		||||
    if (is_doctype_node(node))
 | 
			
		||||
    {
 | 
			
		||||
        ps->doctype = node;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // This is a node with no children, but the only such valid json nodes are
 | 
			
		||||
    // the empty object _ ---> {} or _(A) ---> [].
 | 
			
		||||
    if (is_leaf_node(node))
 | 
			
		||||
    if (is_leaf_node(node) && container)
 | 
			
		||||
    {
 | 
			
		||||
        return json_print_leaf_node(ps, container, node, total, used);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -7578,8 +7662,12 @@ void json_print_array_with_children(XMQPrintState *ps,
 | 
			
		|||
        // Top level object or object inside array. [ {} {} ]
 | 
			
		||||
        // Dump the element name! It cannot be represented!
 | 
			
		||||
    }
 | 
			
		||||
    while (xml_prev_sibling((xmlNode*)from)) from = xml_prev_sibling((xmlNode*)from);
 | 
			
		||||
    assert(from != NULL);
 | 
			
		||||
 | 
			
		||||
    if (from)
 | 
			
		||||
    {
 | 
			
		||||
        while (xml_prev_sibling((xmlNode*)from)) from = xml_prev_sibling((xmlNode*)from);
 | 
			
		||||
        assert(from != NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    json_print_array_nodes(ps, NULL, (xmlNode*)from, (xmlNode*)to);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7667,22 +7755,24 @@ void json_print_element_with_children(XMQPrintState *ps,
 | 
			
		|||
 | 
			
		||||
    ps->line_indent += ps->output_settings->add_indent;
 | 
			
		||||
 | 
			
		||||
    if (ps->doctype)
 | 
			
		||||
    while (!container && ps->pre_nodes && ps->pre_nodes->size > 0)
 | 
			
		||||
    {
 | 
			
		||||
        // Print !DOCTYPE inside top level object.
 | 
			
		||||
        // I.e. !DOCTYPE=html html { body = a } -> { "!DOCTYPE":"html", "html":{ "body":"a"}}
 | 
			
		||||
        print_utf8(ps, COLOR_none, 1, "\"!DOCTYPE\":", NULL);
 | 
			
		||||
        ps->last_char = ':';
 | 
			
		||||
        xmlBuffer *buffer = xmlBufferCreate();
 | 
			
		||||
        xmlNodeDump(buffer, (xmlDocPtr)ps->doq->docptr_.xml, (xmlNodePtr)ps->doctype, 0, 0);
 | 
			
		||||
        char *c = (char*)xmlBufferContent(buffer);
 | 
			
		||||
        char *quoted_value = xmq_quote_as_c(c+10, c+strlen(c)-1);
 | 
			
		||||
        print_utf8(ps, COLOR_none, 3, "\"", NULL, quoted_value, NULL, "\"", NULL);
 | 
			
		||||
        free(quoted_value);
 | 
			
		||||
        xmlBufferFree(buffer);
 | 
			
		||||
        ps->doctype = NULL;
 | 
			
		||||
        ps->last_char = '"';
 | 
			
		||||
        xmlNodePtr node = (xmlNodePtr)rock_stack(ps->pre_nodes);
 | 
			
		||||
 | 
			
		||||
        if (is_doctype_node(node))
 | 
			
		||||
        {
 | 
			
		||||
            json_print_doctype_node(ps, node);
 | 
			
		||||
        }
 | 
			
		||||
        else if (is_comment_node(node))
 | 
			
		||||
        {
 | 
			
		||||
            json_print_comment_node(ps, node, true, ps->pre_post_num_comments_total, ps->pre_post_num_comments_used++);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            assert(false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const char *name = xml_element_name(node);
 | 
			
		||||
    bool is_underline = (name[0] == '_' && name[1] == 0);
 | 
			
		||||
    if (!container && name && !is_underline)
 | 
			
		||||
| 
						 | 
				
			
			@ -7698,11 +7788,28 @@ void json_print_element_with_children(XMQPrintState *ps,
 | 
			
		|||
 | 
			
		||||
    json_print_attributes(ps, node);
 | 
			
		||||
 | 
			
		||||
    while (xml_prev_sibling((xmlNode*)from)) from = xml_prev_sibling((xmlNode*)from);
 | 
			
		||||
    assert(from != NULL);
 | 
			
		||||
    if (from)
 | 
			
		||||
    {
 | 
			
		||||
        while (xml_prev_sibling((xmlNode*)from)) from = xml_prev_sibling((xmlNode*)from);
 | 
			
		||||
        assert(from != NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    json_print_object_nodes(ps, node, (xmlNode*)from, (xmlNode*)to);
 | 
			
		||||
 | 
			
		||||
    while (!container && ps->post_nodes && ps->post_nodes->size > 0)
 | 
			
		||||
    {
 | 
			
		||||
        xmlNodePtr node = (xmlNodePtr)rock_stack(ps->post_nodes);
 | 
			
		||||
 | 
			
		||||
        if (is_comment_node(node))
 | 
			
		||||
        {
 | 
			
		||||
            json_print_comment_node(ps, node, true, ps->pre_post_num_comments_total, ps->pre_post_num_comments_used++);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            assert(false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ps->line_indent -= ps->output_settings->add_indent;
 | 
			
		||||
 | 
			
		||||
    print_utf8(ps, COLOR_brace_right, 1, "}", NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -7800,16 +7907,50 @@ void json_print_comma(XMQPrintState *ps)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void json_print_comment_node(XMQPrintState *ps,
 | 
			
		||||
                             xmlNode *node)
 | 
			
		||||
                             xmlNode *node,
 | 
			
		||||
                             bool prefix_ul,
 | 
			
		||||
                             size_t total,
 | 
			
		||||
                             size_t used)
 | 
			
		||||
{
 | 
			
		||||
    json_check_comma(ps);
 | 
			
		||||
 | 
			
		||||
    print_utf8(ps, COLOR_equals, 1, "\"//\":", NULL);
 | 
			
		||||
    if (prefix_ul) print_utf8(ps, COLOR_equals, 1, "\"_//", NULL);
 | 
			
		||||
    else print_utf8(ps, COLOR_equals, 1, "\"//", NULL);
 | 
			
		||||
 | 
			
		||||
    if (total > 1)
 | 
			
		||||
    {
 | 
			
		||||
        char buf[32];
 | 
			
		||||
        buf[31] = 0;
 | 
			
		||||
        snprintf(buf, 32, "[%zu]\":", used);
 | 
			
		||||
        print_utf8(ps, COLOR_equals, 1, buf, NULL);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        print_utf8(ps, COLOR_equals, 1, "\":", NULL);
 | 
			
		||||
    }
 | 
			
		||||
    ps->last_char = ':';
 | 
			
		||||
    json_print_value(ps, node, node, LEVEL_XMQ, true);
 | 
			
		||||
    ps->last_char = '"';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void json_print_doctype_node(XMQPrintState *ps, xmlNodePtr node)
 | 
			
		||||
{
 | 
			
		||||
    json_check_comma(ps);
 | 
			
		||||
 | 
			
		||||
    // Print !DOCTYPE inside top level object.
 | 
			
		||||
    // I.e. !DOCTYPE=html html { body = a } -> { "!DOCTYPE":"html", "html":{ "body":"a"}}
 | 
			
		||||
    print_utf8(ps, COLOR_none, 1, "\"!DOCTYPE\":", NULL);
 | 
			
		||||
    ps->last_char = ':';
 | 
			
		||||
    xmlBuffer *buffer = xmlBufferCreate();
 | 
			
		||||
    xmlNodeDump(buffer, (xmlDocPtr)ps->doq->docptr_.xml, node, 0, 0);
 | 
			
		||||
    char *c = (char*)xmlBufferContent(buffer);
 | 
			
		||||
    char *quoted_value = xmq_quote_as_c(c+10, c+strlen(c)-1);
 | 
			
		||||
    print_utf8(ps, COLOR_none, 3, "\"", NULL, quoted_value, NULL, "\"", NULL);
 | 
			
		||||
    free(quoted_value);
 | 
			
		||||
    xmlBufferFree(buffer);
 | 
			
		||||
    ps->last_char = '"';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void json_print_entity_node(XMQPrintState *ps, xmlNodePtr node)
 | 
			
		||||
{
 | 
			
		||||
    json_check_comma(ps);
 | 
			
		||||
| 
						 | 
				
			
			@ -7944,6 +8085,46 @@ void xmq_fixup_json_before_writeout(XMQDoc *doq)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void collect_leading_ending_comments_doctype(XMQPrintState *ps, xmlNodePtr *first, xmlNodePtr *last)
 | 
			
		||||
{
 | 
			
		||||
    xmlNodePtr f = *first;
 | 
			
		||||
    xmlNodePtr l = *last;
 | 
			
		||||
    xmlNodePtr node;
 | 
			
		||||
 | 
			
		||||
    for (node = f; node && node != l; node = node->next)
 | 
			
		||||
    {
 | 
			
		||||
        if (is_doctype_node(node) || is_comment_node(node))
 | 
			
		||||
        {
 | 
			
		||||
            push_stack(ps->pre_nodes, node);
 | 
			
		||||
            if (is_comment_node(node)) ps->pre_post_num_comments_total++;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (*first != node)
 | 
			
		||||
    {
 | 
			
		||||
        *first = node;
 | 
			
		||||
        f = node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (node = l; node && node != f; node = node->prev)
 | 
			
		||||
    {
 | 
			
		||||
        if (is_comment_node(node))
 | 
			
		||||
        {
 | 
			
		||||
            push_stack(ps->post_nodes, node);
 | 
			
		||||
            ps->pre_post_num_comments_total++;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (*last != node)
 | 
			
		||||
    {
 | 
			
		||||
        *last = node;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
// Empty function when XMQ_NO_JSON is defined.
 | 
			
		||||
| 
						 | 
				
			
			@ -7962,6 +8143,10 @@ void json_print_object_nodes(XMQPrintState *ps, xmlNode *container, xmlNode *fro
 | 
			
		|||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void collect_leading_ending_comments_doctype(XMQPrintState *ps, xmlNodePtr *first, xmlNodePtr *last)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void json_print_array_nodes(XMQPrintState *ps, xmlNode *container, xmlNode *from, xmlNode *to)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								test.sh
								
								
								
								
							
							
						
						
									
										3
									
								
								test.sh
								
								
								
								
							| 
						 | 
				
			
			@ -203,6 +203,9 @@ if [ "$?" != "0" ]; then RC="1"; fi
 | 
			
		|||
./tests/test_loadable_drivers.sh $PROG
 | 
			
		||||
if [ "$?" != "0" ]; then RC="1"; fi
 | 
			
		||||
 | 
			
		||||
tests/test_force_scaling.sh $PROG
 | 
			
		||||
if [ "$?" != "0" ]; then RC="1"; fi
 | 
			
		||||
 | 
			
		||||
./tests/test_dyndriver_key_with_date.sh $PROG
 | 
			
		||||
if [ "$?" != "0" ]; then RC="1"; fi
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -264,6 +264,8 @@ Energy
 | 
			
		|||
Reactive_Energy
 | 
			
		||||
Apparent_Energy
 | 
			
		||||
Power
 | 
			
		||||
Reactive_Power
 | 
			
		||||
Apparent_Power
 | 
			
		||||
Volume
 | 
			
		||||
Flow
 | 
			
		||||
Voltage
 | 
			
		||||
| 
						 | 
				
			
			@ -307,6 +309,8 @@ Energy
 | 
			
		|||
Reactive_Energy
 | 
			
		||||
Apparent_Energy
 | 
			
		||||
Power
 | 
			
		||||
Reactive_Power
 | 
			
		||||
Apparent_Power
 | 
			
		||||
Volume
 | 
			
		||||
Flow
 | 
			
		||||
Voltage
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,92 @@
 | 
			
		|||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
PROG="$1"
 | 
			
		||||
 | 
			
		||||
rm -rf testoutput
 | 
			
		||||
mkdir -p testoutput
 | 
			
		||||
TEST=testoutput
 | 
			
		||||
 | 
			
		||||
TESTNAME="Test force_scale."
 | 
			
		||||
TESTRESULT="ERROR"
 | 
			
		||||
 | 
			
		||||
cat <<EOF > $TEST/test.xmq
 | 
			
		||||
driver {
 | 
			
		||||
    name           = ime
 | 
			
		||||
    default_fields = alfa_kwh,beta_kwh,gamma_kwh,delta_kwh
 | 
			
		||||
    meter_type     = ElectricityMeter
 | 
			
		||||
    detect {
 | 
			
		||||
        mvt = IME,55,08
 | 
			
		||||
    }
 | 
			
		||||
    field {
 | 
			
		||||
        name           = alfa
 | 
			
		||||
        quantity       = Energy
 | 
			
		||||
        vif_scaling    = None
 | 
			
		||||
        dif_signedness = Unsigned
 | 
			
		||||
        display_unit   = kwh
 | 
			
		||||
        force_scale    = 1
 | 
			
		||||
        match {
 | 
			
		||||
            difvifkey = 849010FF80843B
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    field {
 | 
			
		||||
        name           = beta
 | 
			
		||||
        quantity       = Energy
 | 
			
		||||
        vif_scaling    = None
 | 
			
		||||
        dif_signedness = Unsigned
 | 
			
		||||
        display_unit   = kwh
 | 
			
		||||
        force_scale    = 1/3
 | 
			
		||||
        match {
 | 
			
		||||
            difvifkey = 849010FF80843B
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    field {
 | 
			
		||||
        name           = gamma
 | 
			
		||||
        quantity       = Energy
 | 
			
		||||
        vif_scaling    = None
 | 
			
		||||
        dif_signedness = Unsigned
 | 
			
		||||
        display_unit   = kwh
 | 
			
		||||
        force_scale    = 1000.0
 | 
			
		||||
        match {
 | 
			
		||||
            difvifkey = 849010FF80843B
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    field {
 | 
			
		||||
        name           = delta
 | 
			
		||||
        quantity       = Energy
 | 
			
		||||
        vif_scaling    = None
 | 
			
		||||
        dif_signedness = Unsigned
 | 
			
		||||
        display_unit   = kwh
 | 
			
		||||
        force_scale    = 3.3/3.3
 | 
			
		||||
        match {
 | 
			
		||||
            difvifkey = 849010FF80843B
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
$PROG --format=fields \
 | 
			
		||||
      68CBCB6808017278563412A525660267000000849010FF80843B7A820700849010FF80843C00000000849010FF81843BF35B0400849010FF81843C010000008410FF80843B427107008420FF80843B381100008410FF80843C000000008420FF80843C000000008410FF81843B5A4F04008420FF81843B980C00008410FF81843C010000008420FF81843C0000000084A010FF80843B7A82070084A010FF80843C0000000084A010FF81843BF35B040084A010FF81843C0100000004FF90290000000002FF912B00001F0000000000f11623442D2C998734761B168D2087D19EAD217F1779EDA86AB6_710008190000081900007F13 \
 | 
			
		||||
      METERU $TEST/test.xmq 12345678 NOKEY \
 | 
			
		||||
      > $TEST/test_output.txt
 | 
			
		||||
 | 
			
		||||
cat <<EOF > $TEST/test_expected.txt
 | 
			
		||||
492154;164051.333333;492154000;492154
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
if [ "$?" = "0" ]
 | 
			
		||||
then
 | 
			
		||||
    cat $TEST/test_output.txt | sed 's/"timestamp": "....-..-..T..:..:..Z"/"timestamp": "1111-11-11T11:11:11Z"/' > $TEST/test_responses.txt
 | 
			
		||||
    diff $TEST/test_expected.txt $TEST/test_responses.txt
 | 
			
		||||
    if [ "$?" = "0" ]
 | 
			
		||||
    then
 | 
			
		||||
        echo "OK: $TESTNAME"
 | 
			
		||||
        TESTRESULT="OK"
 | 
			
		||||
    else
 | 
			
		||||
        if [ "$USE_MELD" = "true" ]
 | 
			
		||||
        then
 | 
			
		||||
            meld $TEST/test_expected.txt $TEST/test_responses.txt
 | 
			
		||||
        fi
 | 
			
		||||
    fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ "$TESTRESULT" = "ERROR" ]; then echo ERROR: $TESTNAME;  exit 1; fi
 | 
			
		||||
		Ładowanie…
	
		Reference in New Issue