• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nasa / trick / 21192220067

21 Jan 2026 12:15AM UTC coverage: 55.577% (-0.003%) from 55.58%
21192220067

Pull #2028

github

web-flow
Merge f43251a11 into 771012348
Pull Request #2028: Fixed the condition for stl only case so char* or char[] size calculation gets to normal handling

1 of 3 new or added lines in 1 file covered. (33.33%)

125 existing lines in 5 files now uncovered.

12506 of 22502 relevant lines covered (55.58%)

296541.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.43
/trick_source/sim_services/VariableServer/VariableReference.cpp
1
#include <stdlib.h>
2
#include <iostream>
3
#include <udunits2.h>
4
#include <math.h> // for fpclassify
5
#include <iomanip> // for setprecision
6
#include <string.h>
7
#include <sstream>
8

9
#include "trick/VariableReference.hh"
10
#include "trick/memorymanager_c_intf.h"
11
#include "trick/wcs_ext.h"
12
#include "trick/map_trick_units_to_udunits.hh"
13
#include "trick/message_proto.h"
14
#include "trick/message_type.h"
15
#include "trick/UdUnits.hh"
16
#include "trick/bitfield_proto.h"
17
#include "trick/trick_byteswap.h"
18

19

20
// Static variables to be addresses that are known to be the error ref address
21
int Trick::VariableReference::_bad_ref_int = 0 ;
22
int Trick::VariableReference::_do_not_resolve_bad_ref_int = 0 ;
23

24
REF2* Trick::VariableReference::make_error_ref(std::string in_name) {
3✔
25
    REF2* new_ref;
26
    new_ref = (REF2*)calloc(1, sizeof(REF2));
3✔
27
    new_ref->reference = strdup(in_name.c_str()) ;
3✔
28
    new_ref->units = NULL ;
3✔
29
    new_ref->address = (char *)&_bad_ref_int ;
3✔
30
    new_ref->attr = (ATTRIBUTES*)calloc(1, sizeof(ATTRIBUTES)) ;
3✔
31
    new_ref->attr->type = TRICK_NUMBER_OF_TYPES ;
3✔
32
    new_ref->attr->units = (char *)"--" ;
3✔
33
    new_ref->attr->size = sizeof(int) ;
3✔
34
    return new_ref;
3✔
35
}
36

37
REF2* Trick::VariableReference::make_do_not_resolve_ref(std::string in_name) {
1✔
38
    REF2* new_ref;
39
    new_ref = (REF2*)calloc(1, sizeof(REF2));
1✔
40
    new_ref->reference = strdup(in_name.c_str()) ;
1✔
41
    new_ref->units = NULL ;
1✔
42
    new_ref->address = (char *)&_do_not_resolve_bad_ref_int ;
1✔
43
    new_ref->attr = (ATTRIBUTES*)calloc(1, sizeof(ATTRIBUTES)) ;
1✔
44
    new_ref->attr->type = TRICK_NUMBER_OF_TYPES ;
1✔
45
    new_ref->attr->units = (char *)"--" ;
1✔
46
    new_ref->attr->size = sizeof(int) ;
1✔
47
    return new_ref;
1✔
48
}
49

50
// Helper function to deal with time variable
51
REF2* make_time_ref(double * time) {
×
52
    REF2* new_ref;
53
    new_ref = (REF2*)calloc(1, sizeof(REF2));
×
54
    new_ref->reference = strdup("time") ;
×
55
    new_ref->units = strdup("s") ;
×
56
    new_ref->address = (char *)time ;
×
57
    new_ref->attr = (ATTRIBUTES*)calloc(1, sizeof(ATTRIBUTES)) ;
×
58
    new_ref->attr->type = TRICK_DOUBLE ;
×
59
    new_ref->attr->units = strdup("s") ;
×
60
    new_ref->attr->size = sizeof(double) ;
×
61
    return new_ref;
×
62
}
63

64
Trick::VariableReference::VariableReference(std::string var_name, double* time) : _staged(false), _write_ready(false) {
×
65
    if (var_name != "time") {
×
66
        ASSERT(0);
67
    }
68

69
    _var_info = make_time_ref(time);
×
70

71
    // Set up member variables
72
    _address = _var_info->address;
×
73
    _size = _var_info->attr->size ;
×
74
    _deref = false;
×
75

76
    // Deal with weirdness around string vs wstring
77
    _trick_type = _var_info->attr->type ;
×
78

79
    // Allocate stage and write buffers
80
    _stage_buffer = calloc(_size, 1) ;
×
81
    _write_buffer = calloc(_size, 1) ;
×
82

83
    _conversion_factor = cv_get_trivial();
×
84
    _base_units = _var_info->attr->units;
×
85
    _requested_units = "s";
×
86
    _name = _var_info->reference;
×
87
}
×
88

89
Trick::VariableReference::VariableReference(std::string var_name) : _staged(false), _write_ready(false) {
8,056✔
90

91
    if (var_name == "time") {
8,056✔
92
        ASSERT(0);
93
    } else {
94
        // get variable attributes from memory manager
95
        _var_info = ref_attributes(var_name.c_str());
8,056✔
96
    }
97

98
    // Handle error cases
99
    if ( _var_info == NULL ) {
8,056✔
100
        // TODO: ERROR LOGGER sendErrorMessage("Variable Server could not find variable %s.\n", var_name);
101
        // PRINTF IS NOT AN ERROR LOGGER @me
102
        message_publish(MSG_ERROR, "Variable Server could not find variable %s.\n", var_name.c_str());
1✔
103
        _var_info = make_error_ref(var_name);
1✔
104
    } else if ( _var_info->attr ) {
8,055✔
105
        if ( _var_info->attr->type == TRICK_STRUCTURED ) {
8,055✔
106
            // sendErrorMessage("Variable Server: var_add cant add \"%s\" because its a composite variable.\n", var_name);
107
            message_publish(MSG_ERROR, "Variable Server: var_add cant add \"%s\" because its a composite variable.\n", var_name.c_str());
1✔
108

109
            free(_var_info);
1✔
110
            _var_info = make_do_not_resolve_ref(var_name);
1✔
111
        }
112
    } else {
113
        // sendErrorMessage("Variable Server: BAD MOJO - Missing ATTRIBUTES.");
114
        message_publish(MSG_ERROR, "Variable Server: BAD MOJO - Missing ATTRIBUTES.");
×
115

116
        free(_var_info);
×
117
        _var_info = make_error_ref(var_name);
×
118
    }
119

120
    // Set up member variables
121
    _var_info->units = NULL;
8,056✔
122
    _address = _var_info->address;
8,056✔
123
    _size = _var_info->attr->size ;
8,056✔
124
    _deref = false;
8,056✔
125

126
    // Deal with weirdness around string vs wstring
127
    _trick_type = _var_info->attr->type ;
8,056✔
128

129
    // Special handling for indexed STL containers (e.g., vec[0], point_vec[0].x)
130
    // We need to detect two cases:
131
    // 1. Final attr is TRICK_STL AND we indexed it (e.g., vec[0]) - update type/size to element
132
    // 2. Pattern "]." in reference - we indexed something then accessed a member (e.g., point_vec[0].x)
133
    // 
134
    // For case 1, we need to update _trick_type and _size to match the element type.
135
    // For case 2, the final attr is already the member's attributes (e.g., double x), so _trick_type
136
    // and _size are already correct - we just need to set the flag to skip follow_address_path().
137
    //
138
    // Important: If reference is just "vec" (no indexing), keep it as TRICK_STL container type.
139
    _used_stl_indexing = false;
8,056✔
140
    if ( _var_info->attr->type == TRICK_STL && _var_info->reference ) {
8,056✔
141
        // Check if the STL container was actually indexed by checking if reference ends with ']'
142
        // e.g., "vec[0]" ends with ']', but "vec" or "xxx[0].vec" do not
143
        size_t len = strlen(_var_info->reference);
2✔
144
        bool stl_was_indexed = (len > 0 && _var_info->reference[len - 1] == ']');
2✔
145

146
        if (stl_was_indexed) {
2✔
147
            // Case 1: Final attr is STL container AND we indexed it (e.g., vec[0])
148
            // Update type and size to match the element, not the container
149
            _trick_type = _var_info->attr->stl_elem_type;
1✔
150
            _used_stl_indexing = true;
1✔
151

152
            // Update _size to match the element type size, not the container size
153
            switch (_trick_type) {
1✔
154
                case TRICK_CHARACTER:
×
155
                case TRICK_UNSIGNED_CHARACTER:
156
                case TRICK_BOOLEAN:
157
                    _size = sizeof(char);
×
158
                    break;
×
159
                case TRICK_SHORT:
×
160
                case TRICK_UNSIGNED_SHORT:
161
                    _size = sizeof(short);
×
162
                    break;
×
163
                case TRICK_INTEGER:
1✔
164
                case TRICK_UNSIGNED_INTEGER:
165
                case TRICK_ENUMERATED:
166
                    _size = sizeof(int);
1✔
167
                    break;
1✔
168
                case TRICK_LONG:
×
169
                case TRICK_UNSIGNED_LONG:
170
                    _size = sizeof(long);
×
171
                    break;
×
172
                case TRICK_LONG_LONG:
×
173
                case TRICK_UNSIGNED_LONG_LONG:
174
                    _size = sizeof(long long);
×
175
                    break;
×
176
                case TRICK_FLOAT:
×
177
                    _size = sizeof(float);
×
178
                    break;
×
179
                case TRICK_DOUBLE:
×
180
                    _size = sizeof(double);
×
181
                    break;
×
182
                case TRICK_STRING:
×
183
                case TRICK_WSTRING:
184
                case TRICK_STRUCTURED:
185
                    _size = sizeof(void*);
×
186
                    break;
×
187
                default:
×
188
                    // Keep existing size for unknown types
189
                    break;
×
190
            }
191

192
            // address already points to the element from ref_dim
193
            // Treat as single value - nothing else necessary
194
        }
2✔
195
    } else if ( _var_info->reference && strstr(_var_info->reference, "].") &&
8,054✔
NEW
196
                _var_info->pointer_present == 0 &&
×
NEW
197
                (_var_info->attr->type != TRICK_CHARACTER && _var_info->attr->type != TRICK_WCHAR) ) {
×
198
        // Case 2: Pattern "]." indicates indexing followed by member access (e.g., point_vec[0].x)
199
        // IMPORTANT: This is specifically for STL containers where follow_address_path() doesn't work.
200
        // For regular pointer arrays including TRICK_CHARACTER/WCHAR pointer arrays, pointer_present will be set,
201
        // or simple TRICK_CHARACTER/WCHAR array, the normal flow below under constrained array or unconstrained array
202
        // will calculate the size correctly.
203
        // So only use this special handling if there's NO pointer or not TRICK_CHARACTER/TRICK_WCHAR in the path (STL-only case).
204
        // Check if the last "]." is followed only by member names (no more ']')
205
        const char* last_bracket_dot = strstr(_var_info->reference, "].");
×
206
        // Find the last occurrence of "]."
207
        const char* temp = last_bracket_dot;
×
208
        while (temp != NULL && (temp = strstr(temp + 2, "].")) != NULL) {
×
209
            last_bracket_dot = temp;
×
210
        }
211
        // After the last "].", check if there are no more ']'
212
        if (strchr(last_bracket_dot + 2, ']') == NULL) {
×
213
            // The final attr is already the member's attributes, so _trick_type and _size are correct.
214
            // Just set the flag to skip follow_address_path() which doesn't understand STL indexing.
215
            // Note: This also matches pointer arrays like ptr_array[0].x, but that's okay - the address
216
            // is already correct and skipping follow_address_path() won't hurt.
217
            _used_stl_indexing = true;
×
218
        }
×
219
    } else if ( _var_info->num_index == _var_info->attr->num_index ) {
8,054✔
220
        // single value - nothing else necessary
221
    } else if ( _var_info->attr->index[_var_info->attr->num_index - 1].size != 0 ) {
10✔
222
        // Constrained array
223
        for ( int i = _var_info->attr->num_index-1;  i > _var_info->num_index-1 ; i-- ) {
23✔
224
            _size *= _var_info->attr->index[i].size ;
13✔
225
        }
226
    } else {
227
        // Unconstrained array
228
        if ((_var_info->attr->num_index - _var_info->num_index) > 1 ) {
×
229
            message_publish(MSG_ERROR, "Variable Server Error: var_add(%s) requests more than one dimension of dynamic array.\n", _var_info->reference);
×
UNCOV
230
            message_publish(MSG_ERROR, "Data is not contiguous so returned values are unpredictable.\n") ;
×
231
        }
UNCOV
232
        if ( _var_info->attr->type == TRICK_CHARACTER ) {
×
UNCOV
233
            _trick_type = TRICK_STRING ;
×
UNCOV
234
            _deref = true;
×
UNCOV
235
        } else if ( _var_info->attr->type == TRICK_WCHAR ) {
×
UNCOV
236
            _trick_type = TRICK_WSTRING ;
×
UNCOV
237
            _deref = true;
×
238
        } else {
UNCOV
239
            _deref = true ;
×
UNCOV
240
            _size *= get_size((char*)_address) ;
×
241
        }
242
    }
243
    // handle strings: set a max buffer size, the copy size may vary so will be set in copy_sim_data
244
    if (( _trick_type == TRICK_STRING ) || ( _trick_type == TRICK_WSTRING )) {
8,056✔
245
        _size = MAX_ARRAY_LENGTH ;
6✔
246
    }
247

248
    // Allocate stage and write buffers
249
    _stage_buffer = calloc(_size, 1) ;
8,056✔
250
    _write_buffer = calloc(_size, 1) ;
8,056✔
251

252
    _conversion_factor = cv_get_trivial();
8,056✔
253
    _base_units = _var_info->attr->units;
8,056✔
254
    _requested_units = "";
8,056✔
255
    _name = _var_info->reference;
8,056✔
256

257
    // Done!
258
}
8,056✔
259

260
Trick::VariableReference::~VariableReference() {
56✔
261
    if (_var_info != NULL) {
56✔
262
        free( _var_info );
56✔
263
        _var_info = NULL;
56✔
264
    }
265
    if (_stage_buffer != NULL) {
56✔
266
        free (_stage_buffer);
56✔
267
        _stage_buffer = NULL;
56✔
268
    }
269
    if (_write_buffer != NULL) {
56✔
270
        free (_write_buffer);
56✔
271
        _write_buffer = NULL;
56✔
272
    }
273
    if (_conversion_factor != NULL) {
56✔
274
        cv_free(_conversion_factor);
56✔
275
    }
276
}
56✔
277

278
std::string Trick::VariableReference::getName() const {
12,021✔
279
    return _name;
12,021✔
280
}
281

282
int Trick::VariableReference::getSizeBinary() const {
4,000✔
283
    return _size;
4,000✔
284
}
285

286
TRICK_TYPE Trick::VariableReference::getType() const {
4✔
287
    return _trick_type;
4✔
288
}
289

290
std::string Trick::VariableReference::getBaseUnits() const {
12✔
291
    return _base_units;
12✔
292
}
293

294
int Trick::VariableReference::setRequestedUnits(std::string units_name) {
10✔
295
    // Some error logging lambdas - these should probably go somewhere else
296
    // But I do kinda like them
297
    auto publish = [](MESSAGE_TYPE type, const std::string& message) {
2✔
298
        std::ostringstream oss;
2✔
299
        oss << "Variable Server: " << message << std::endl;
2✔
300
        message_publish(type, oss.str().c_str());
2✔
301
    };
2✔
302

303
    auto publishError = [&](const std::string& units) {
1✔
304
        std::ostringstream oss;
1✔
305
        oss << "units error for [" << getName() << "] [" << units << "]";
1✔
306
        publish(MSG_ERROR, oss.str());
1✔
307
    };
1✔
308

309
    // If the units_name parameter is "xx", set it to the current units.
310
    if (!units_name.compare("xx")) {
10✔
UNCOV
311
        units_name = getBaseUnits();
×
312
    }
313

314
    // Don't try to convert units for a bad ref
315
    if (_var_info->address == &_bad_ref_int) {
10✔
316
        return -1 ;
×
317
    }
318

319
    // if unitless ('--') then do not convert to udunits 
320
    if (units_name.compare("--")) {
10✔
321
        // Check to see if this is an old style Trick unit that needs to be converted to new udunits
322
        std::string new_units = map_trick_units_to_udunits(units_name) ;
10✔
323
        // Warn if a conversion has taken place
324
        if ( units_name.compare(new_units) ) {
10✔
325
            // TODO: MAKE BETTER SYSTEM FOR ERROR LOGGING
326
            std::ostringstream oss;
×
327
            oss << "[" << getName() << "] old-style units converted from ["
×
UNCOV
328
                << units_name << "] to [" << new_units << "]";
×
UNCOV
329
            publish(MSG_WARNING, oss.str());
×
330
        }
331

332
        // Interpret base unit
333
        ut_unit * from = ut_parse(Trick::UdUnits::get_u_system(), getBaseUnits().c_str(), UT_ASCII) ;
10✔
334
        if ( !from ) {
10✔
UNCOV
335
            std::cout << "Error in interpreting base units" << std::endl;
×
UNCOV
336
            publishError(getBaseUnits());
×
UNCOV
337
            ut_free(from) ;
×
UNCOV
338
            return -1 ;
×
339
        }
340

341
        // Interpret requested unit
342
        ut_unit * to = ut_parse(Trick::UdUnits::get_u_system(), new_units.c_str(), UT_ASCII) ;
10✔
343
        if ( !to ) {
10✔
344
            std::cout << "Error in interpreting requested units" << std::endl;
1✔
345
            publishError(new_units);
1✔
346
            ut_free(from) ;
1✔
347
            ut_free(to) ;
1✔
348
            return -1 ;
1✔
349
        }
350

351
        // Create a converter from the base to the requested
352
        auto new_conversion_factor = ut_get_converter(from, to) ;
9✔
353
        ut_free(from) ;
9✔
354
        ut_free(to) ;
9✔
355
        if ( !new_conversion_factor ) {
9✔
356
            std::ostringstream oss;
1✔
357
            oss << "[" << getName() << "] cannot convert units from [" << getBaseUnits()
1✔
358
                << "] to [" << new_units << "]";
1✔
359
            publish(MSG_ERROR, oss.str());
1✔
360
            return -1 ;
1✔
361
        } else {
362
            _conversion_factor = new_conversion_factor;
8✔
363
        }
364
    
365
        // Set the requested units. This will cause the unit string to be printed in write_value_ascii
366
        _requested_units = new_units;
8✔
367
    }
368
    return 0;
8✔
369
}
370

371
int Trick::VariableReference::stageValue(bool validate_address) {
8,039✔
372
    _write_ready = false;
8,039✔
373

374
    // Copy <size> bytes from <address> to staging_point.
375

376
    // Try to recreate connection if it has been broken
377
    if (_var_info->address == &_bad_ref_int) {
8,039✔
378
        REF2 *new_ref = ref_attributes(_var_info->reference);
1✔
379
        if (new_ref != NULL) {
1✔
UNCOV
380
            _var_info = new_ref;
×
381
            _address = _var_info->address;
×
382
            // _requested_units = "";
383
        }
384
    }
385

386
    // if there's a pointer somewhere in the address path, follow it in case pointer changed
387
    // BUT: if we've indexed into an STL container, then the address already points to the correct location
388
    // and follow_address_path would incorrectly recalculate it (it doesn't understand STL indexing)
389
    // Use the _used_stl_indexing flag that was set during construction when we detected STL indexing
390
    // (when num_index > attr->num_index and attr->type == TRICK_STL)
391
    if ( _var_info->pointer_present == 1 && !_used_stl_indexing ) {
8,039✔
UNCOV
392
        _address = follow_address_path(_var_info) ;
×
UNCOV
393
        if (_address == NULL) {
×
UNCOV
394
            tagAsInvalid();
×
UNCOV
395
        } else if ( validate_address ) {
×
UNCOV
396
            validate();
×
397
        } else {
UNCOV
398
            _var_info->address = _address ;
×
399
        }
400
    }
401

402
    // if this variable is a string we need to get the raw character string out of it.
403
    if (( _trick_type == TRICK_STRING ) && !_deref) {
8,039✔
404
        std::string * str_ptr = (std::string *)_var_info->address ;
5✔
405
        // Get a pointer to the internal character array
406
        _address = (void *)(str_ptr->c_str()) ;
5✔
407
    }
408

409
    // if this variable itself is a pointer, dereference it
410
    if ( _deref ) {
8,039✔
UNCOV
411
        _address = *(void**)_var_info->address ;
×
412
    }
413

414
    // handle c++ string and char*
415
    if ( _trick_type == TRICK_STRING ) {
8,039✔
416
        if (_address == NULL) {
5✔
UNCOV
417
            _size = 0 ;
×
418
        } else {
419
            _size = strlen((char*)_address) + 1 ;
5✔
420
        }
421
    }
422
    // handle c++ wstring and wchar_t*
423
    if ( _trick_type == TRICK_WSTRING ) {
8,039✔
UNCOV
424
        if (_address == NULL) {
×
UNCOV
425
            _size = 0 ;
×
426
        } else {
UNCOV
427
            _size = wcslen((wchar_t *)_address) * sizeof(wchar_t);
×
428
        }
429
    }
430
    if(_address != NULL) {
8,039✔
431
        memcpy( _stage_buffer , _address , _size ) ;
8,039✔
432
    }
433

434
    _staged = true;
8,039✔
435
    return 0;
8,039✔
436
}
437

438
bool Trick::VariableReference::validate() {
3✔
439
    // The address is not NULL.
440
    // Should be called by VariableServer Session if validateAddress is on.
441
    // check the memory manager if the address falls into
442
    // any of the memory blocks it knows of.  Don't do this if we have a std::string or
443
    // wstring type, or we already are pointing to a bad ref.
444
    if ( (_trick_type != TRICK_STRING) and
9✔
445
            (_trick_type != TRICK_WSTRING) and
3✔
446
            (_var_info->address != &_bad_ref_int) and
8✔
447
            (get_alloc_info_of(_address) == NULL) ) {
2✔
448
        
449
        // This variable is broken, make it into an error ref
450
        tagAsInvalid();
1✔
451
        return false;
1✔
452
    }
453

454
    // Everything is fine
455
    return true;
2✔
456
}
457

458
static void write_escaped_string( std::ostream& os, const char* s) {
4✔
459
    for (int ii=0 ; ii<strlen(s) ; ii++) {
41✔
460
        if (isprint(s[ii])) {
37✔
461
            os << s[ii];
29✔
462
        } else {
463
            switch ((s)[ii]) {
8✔
464
                case '\n': os << "\\n"; break;
2✔
465
                case '\t': os << "\\t"; break;
1✔
466
                case '\b': os << "\\b"; break;
1✔
467
                case '\a': os << "\\a"; break;
1✔
468
                case '\f': os << "\\f"; break;
1✔
469
                case '\r': os << "\\n"; break;
1✔
470
                case '\v': os << "\\v"; break;
1✔
UNCOV
471
                case '\"': os << "\\\""; break;
×
UNCOV
472
                default  : {
×
473
                    // Replicating behavior from original vs_format_ascii
474
                    char temp_s[6];
475
                    sprintf(temp_s, "\\x%02x", s[ii]);
×
476
                    os << temp_s ; 
×
UNCOV
477
                    break;
×
478
                }
479
            }
480
        }
481
    }
482
}
4✔
483

UNCOV
484
int Trick::VariableReference::getSizeAscii() const {
×
UNCOV
485
    std::stringstream ss;
×
UNCOV
486
    writeValueAscii(ss);
×
UNCOV
487
    return ss.str().length();
×
488
}
489

490

491
int Trick::VariableReference::writeValueAscii( std::ostream& out ) const {
4,030✔
492
    // This is copied and modified from vs_format_ascii
493

494
    if (!isWriteReady()) {
4,030✔
495
        return -1;
1✔
496
    }
497

498
    // local_type is set to the type of the attribute, but if it's a STL type, we need to use the element type.
499
    TRICK_TYPE local_type = _trick_type;
4,029✔
500

501
    if (_trick_type == TRICK_STL) {
4,029✔
502
        // If the variable is an STL type, use the STL element type for writting value
UNCOV
503
        local_type = _var_info->attr->stl_elem_type;
×
504
    }
505

506
    int bytes_written = 0;
4,029✔
507
    void * buf_ptr = _write_buffer ;
4,029✔
508
    while (bytes_written < _size) {
8,062✔
509
        bytes_written += _var_info->attr->size ;
4,033✔
510

511
        switch (local_type) {
4,033✔
512

513
        case TRICK_CHARACTER:
2✔
514
            if (_var_info->attr->num_index == _var_info->num_index) {
2✔
515
                // Single char
516
                out << (int)cv_convert_double(_conversion_factor, *(char *)buf_ptr);
1✔
517
            } else {
518
                // All but last dim specified, leaves a char array 
519
                write_escaped_string(out, (const char *) buf_ptr);
1✔
520
                bytes_written = _size ;
1✔
521
            }
522
            break;
2✔
523
        case TRICK_UNSIGNED_CHARACTER:
2✔
524
            if (_var_info->attr->num_index == _var_info->num_index) {
2✔
525
                // Single char
526
                out << (unsigned int)cv_convert_double(_conversion_factor,*(unsigned char *)buf_ptr);
1✔
527
            } else {
528
                // All but last dim specified, leaves a char array 
529
                write_escaped_string(out, (const char *) buf_ptr);
1✔
530
                bytes_written = _size ;
1✔
531
            }
532
            break;
2✔
533

534
        case TRICK_WCHAR:{
2✔
535
                if (_var_info->attr->num_index == _var_info->num_index) {
2✔
536
                    out << *(wchar_t *) buf_ptr;
1✔
537
                } else {
538
                    // convert wide char string char string
539
                    size_t len = wcs_to_ncs_len((wchar_t *)buf_ptr) + 1 ;
2✔
540

541
                    char temp_buf[len];
1✔
542
                    wcs_to_ncs((wchar_t *) buf_ptr, temp_buf, len);
1✔
543
                    out << temp_buf;
1✔
544
                    bytes_written = _size ;
2✔
545
                }
546
            }
547
            break;
2✔
548

549
        case TRICK_STRING:
2✔
550
            if ((char *) buf_ptr != NULL) {
2✔
551
                write_escaped_string(out, (const char *) buf_ptr);
2✔
552
                bytes_written = _size ;
2✔
553
            } else {
554
                out << '\0';
×
555
            }
556
            break;
2✔
557

UNCOV
558
        case TRICK_WSTRING:
×
559
            if ((wchar_t *) buf_ptr != NULL) {
×
560
                // convert wide char string char string
UNCOV
561
                size_t len = wcs_to_ncs_len( (wchar_t *)buf_ptr) + 1 ;
×
562

UNCOV
563
                char temp_buf[len];
×
564
                wcs_to_ncs(  (wchar_t *) buf_ptr, temp_buf, len);
×
565
                out << temp_buf;
×
566
                bytes_written = _size ;
×
567
            } else {
UNCOV
568
                out << '\0';
×
569
            }
UNCOV
570
            break;
×
571
        case TRICK_SHORT:
1✔
572
            out << (short)cv_convert_double(_conversion_factor,*(short *)buf_ptr);
1✔
573
            break;
1✔
574

UNCOV
575
        case TRICK_UNSIGNED_SHORT:
×
UNCOV
576
            out << (unsigned short)cv_convert_double(_conversion_factor,*(unsigned short *)buf_ptr);
×
577
            break;
×
578

579
        case TRICK_INTEGER:
4,012✔
580
        case TRICK_ENUMERATED:
581
            out << (int)cv_convert_double(_conversion_factor,*(int *)buf_ptr);
4,012✔
582
            break;
4,012✔
583

584
        case TRICK_BOOLEAN:
1✔
585
            out << (int)cv_convert_double(_conversion_factor,*(bool *)buf_ptr);
1✔
586
            break;
1✔
587

UNCOV
588
        case TRICK_BITFIELD:
×
UNCOV
589
            out << (GET_BITFIELD(buf_ptr, _var_info->attr->size, _var_info->attr->index[0].start, _var_info->attr->index[0].size));
×
UNCOV
590
            break;
×
591

UNCOV
592
        case TRICK_UNSIGNED_BITFIELD:
×
UNCOV
593
            out << (GET_UNSIGNED_BITFIELD(buf_ptr, _var_info->attr->size, _var_info->attr->index[0].start, _var_info->attr->index[0].size));
×
UNCOV
594
            break;
×
595
            
UNCOV
596
        case TRICK_UNSIGNED_INTEGER:
×
UNCOV
597
            out << (unsigned int)cv_convert_double(_conversion_factor,*(unsigned int *)buf_ptr);
×
UNCOV
598
            break;
×
599

600
        case TRICK_LONG: {
1✔
601
            long l = *(long *)buf_ptr;
1✔
602
            if (_conversion_factor != cv_get_trivial()) {
1✔
603
                l = (long)cv_convert_double(_conversion_factor, l);
1✔
604
            }
605
            out << l;
1✔
606
            break;
1✔
607
        }
608

609
        case TRICK_UNSIGNED_LONG: {
1✔
610
            unsigned long ul = *(unsigned long *)buf_ptr;
1✔
611
            if (_conversion_factor != cv_get_trivial()) {
1✔
612
                ul = (unsigned long)cv_convert_double(_conversion_factor, ul);
1✔
613
            }
614
            out << ul;
1✔
615
            break;
1✔
616
        }
617

UNCOV
618
        case TRICK_FLOAT:
×
UNCOV
619
            out << std::setprecision(8) << cv_convert_float(_conversion_factor,*(float *)buf_ptr);
×
UNCOV
620
            break;
×
621

622
        case TRICK_DOUBLE:
5✔
623
            out << std::setprecision(16) << cv_convert_double(_conversion_factor,*(double *)buf_ptr);
5✔
624
            break;
5✔
625

626
        case TRICK_LONG_LONG: {
1✔
627
            long long ll = *(long long *)buf_ptr;
1✔
628
            if (_conversion_factor != cv_get_trivial()) {
1✔
629
                ll = (long long)cv_convert_double(_conversion_factor, ll);
1✔
630
            }
631
            out << ll;
1✔
632
            break;
1✔
633
        }
634

635
        case TRICK_UNSIGNED_LONG_LONG: {
1✔
636
            unsigned long long ull = *(unsigned long long *)buf_ptr;
1✔
637
            if (_conversion_factor != cv_get_trivial()) {
1✔
638
                ull = (unsigned long long)cv_convert_double(_conversion_factor, ull);
1✔
639
            }
640
            out << ull;
1✔
641
            break;
1✔
642
        }
643

644
        case TRICK_NUMBER_OF_TYPES:
2✔
645
            out << "BAD_REF";
2✔
646
            break;
2✔
647

UNCOV
648
        default:{
×
649

UNCOV
650
            break;
×
651
        }
652
        } // end switch
653

654
        if (bytes_written < _size) {
4,033✔
655
        // if returning an array, continue array as comma separated values
656
            out << ",";
4✔
657
            buf_ptr = (void*) ((long)buf_ptr + _var_info->attr->size) ;
4✔
658
        }
659
    } //end while
660

661
    if (_requested_units != "") {
4,029✔
662
        if ( _var_info->attr->mods & TRICK_MODS_UNITSDASHDASH ) {
8✔
UNCOV
663
            out << " {--}";
×
664
        } else {
665
            out << " {" << _requested_units << "}";
8✔
666
        }
667
    }
668

669
    return 0;
4,029✔
670
}
671

672
void Trick::VariableReference::tagAsInvalid () {
2✔
673
    std::string save_name(getName()) ;
2✔
674
    free(_var_info) ;
2✔
675
    _var_info = make_error_ref(save_name) ;
2✔
676
    _address = _var_info->address ;
2✔
677
}
2✔
678

679

680
int Trick::VariableReference::prepareForWrite() {
8,039✔
681
    if (!_staged) {
8,039✔
682
        return 1;
1✔
683
    }
684

685
    void * temp_p = _stage_buffer;
8,038✔
686
    _stage_buffer = _write_buffer;
8,038✔
687
    _write_buffer = temp_p;
8,038✔
688

689
    _staged = false;
8,038✔
690
    _write_ready = true;
8,038✔
691
    return 0;
8,038✔
692
}
693

694
bool Trick::VariableReference::isStaged() const {
8,003✔
695
    return _staged;
8,003✔
696
}
697

698
bool Trick::VariableReference::isWriteReady() const {
4,035✔
699
    return _write_ready;
4,035✔
700
}
701

702
int Trick::VariableReference::writeTypeBinary( std::ostream& out, bool byteswap ) const {
4,000✔
703
    int local_type = _trick_type;
4,000✔
704
    if (byteswap) {
4,000✔
UNCOV
705
        local_type = trick_byteswap_int(local_type);
×
706
    }
707
    out.write(const_cast<const char *>(reinterpret_cast<char *>(&local_type)), sizeof(int));
4,000✔
708

709
    return 0;
4,000✔
710
}
711

712
int Trick::VariableReference::writeSizeBinary( std::ostream& out, bool byteswap ) const {
4,000✔
713
    int local_size = _size;
4,000✔
714
    if (byteswap) {
4,000✔
UNCOV
715
        local_size = trick_byteswap_int(local_size);
×
716
    }
717
    out.write(const_cast<const char *>(reinterpret_cast<char *>(&local_size)), sizeof(int));
4,000✔
718

719
    return 0;
4,000✔
720
}
721

722
int Trick::VariableReference::writeNameBinary( std::ostream& out, bool byteswap ) const {
4,001✔
723
    std::string name = getName();
4,001✔
724
    out.write(name.c_str(), name.size());
4,001✔
725

726
    return 0;
8,002✔
727
}
728

729
int Trick::VariableReference::writeNameLengthBinary( std::ostream& out, bool byteswap ) const {
4,001✔
730
    int name_size = getName().size();
4,001✔
731
    if (byteswap) {
4,001✔
UNCOV
732
        name_size = trick_byteswap_int(name_size);
×
733
    }
734

735
    out.write(const_cast<const char *>(reinterpret_cast<char *>(&name_size)), sizeof(int));
4,001✔
736

737
    return 0;
4,001✔
738
}
739

740

741
void Trick::VariableReference::byteswap_var (char * out, char * in) const {
1✔
742
    byteswap_var(out, in, *this);
1✔
743
}
1✔
744

745

746
void Trick::VariableReference::byteswap_var (char * out, char * in, const VariableReference& ref) {
9✔
747
    ATTRIBUTES * attr = ref._var_info->attr;
9✔
748
    int array_size = 1;
9✔
749

750
    // Determine how many elements are in this array if it is an array
751
    for (int j = 0; j < ref._var_info->attr->num_index; j++) {
16✔
752
        array_size *= attr->index[j].size;
7✔
753
    }
754

755
    switch (attr->size) {
9✔
756
        case 1:
2✔
757
            // If these are just characters, no need to byteswap
758
            for (int j = 0; j < array_size; j++) {
10✔
759
                out[j] = in[j];
8✔
760
            }
761
            break;
2✔
762

763
        case 2: {
1✔
764
            short * short_in = reinterpret_cast<short *> (in);
1✔
765
            short * short_out = reinterpret_cast<short *> (out);
1✔
766

767
            for (int j = 0; j < array_size; j++) {
2✔
768
                short_out[j] = trick_byteswap_short(short_in[j]);
1✔
769
            }
770
            break;
1✔
771
        }
772

773
        case 4: {
4✔
774
            int * int_in = reinterpret_cast<int *> (in);
4✔
775
            int * int_out = reinterpret_cast<int *> (out);
4✔
776

777
            for (int j = 0; j < array_size; j++) {
131✔
778
                int_out[j] = trick_byteswap_int(int_in[j]);
127✔
779
            }
780
            break;
4✔
781
        }
782
        case 8: {
2✔
783
            // We don't actually care if this is double or long, just that it's the right size
784
            double * double_in = reinterpret_cast<double *> (in);
2✔
785
            double * double_out = reinterpret_cast<double *> (out);
2✔
786

787
            for (int j = 0; j < array_size; j++) {
8✔
788
                double_out[j] = trick_byteswap_double(double_in[j]);
6✔
789
            }
790
            break;
2✔
791
        }
792
    }
793
}
9✔
794

795

796

797
int Trick::VariableReference::writeValueBinary( std::ostream& out, bool byteswap ) const {
4,006✔
798
    // local_type is set to the type of the attribute, but if it's a STL type, we need to use the element type.
799
    TRICK_TYPE local_type = _trick_type;
4,006✔
800
    if (local_type == TRICK_STL) {
4,006✔
801
        // If the variable is an STL type, use the STL element type for writing value
802
        local_type = _var_info->attr->stl_elem_type;
×
803
    }
804

805
    if ( local_type == TRICK_BITFIELD ) {
4,006✔
UNCOV
806
        int temp_i = GET_BITFIELD(_write_buffer , _var_info->attr->size ,
×
807
            _var_info->attr->index[0].start, _var_info->attr->index[0].size) ;
UNCOV
808
        out.write((char *)(&temp_i), _size);
×
UNCOV
809
        return _size;
×
810
    }
811

812
    if ( local_type == TRICK_UNSIGNED_BITFIELD ) {
4,006✔
UNCOV
813
        int temp_unsigned = GET_UNSIGNED_BITFIELD(_write_buffer , _var_info->attr->size ,
×
814
                _var_info->attr->index[0].start, _var_info->attr->index[0].size) ;
UNCOV
815
        out.write((char *)(&temp_unsigned), _size);
×
UNCOV
816
        return _size;
×
817
    }
818

819
    if (local_type ==  TRICK_NUMBER_OF_TYPES) {
4,006✔
820
        // TRICK_NUMBER_OF_TYPES is an error case
UNCOV
821
        int temp_zero = 0 ;
×
UNCOV
822
        out.write((char *)(&temp_zero), _size);
×
UNCOV
823
        return _size;
×
824
    }
825

826
    if (byteswap) {
4,006✔
827
        char * byteswap_buf = (char *) calloc (_size, 1);
1✔
828
        byteswap_var(byteswap_buf, (char *) _write_buffer);
1✔
829
        out.write(byteswap_buf, _size);
1✔
830
        free (byteswap_buf);
1✔
831
    }
832
    else {
833
        out.write((char *) _write_buffer, _size);
4,005✔
834
    }
835

836
    return _size;
4,006✔
837
    
838
}  
839

840
std::ostream& Trick::operator<< (std::ostream& s, const Trick::VariableReference& ref) {
6✔
841
    s << "      \"" << ref.getName() << "\"";
6✔
842
    return s;
6✔
843
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc