roller1.inc
1 // -*- C -*- 2 // SPDX-FileCopyrightText: 2023-2025 Le'Sec Core collective 3 // 4 // SPDX-License-Identifier: LGPL-3.0-or-later 5 6 // This is purely internal, for testing purposes 7 8 #include <stdlib.h> 9 #include <stdio.h> 10 #include <assert.h> 11 #include "roller.h" 12 13 struct test_roller1_data_t { 14 # define TEST_INNER_ROLL_MIN_SIZE 2 15 # define TEST_INNER_ROLL_MAX_SIZE 5 16 unsigned int inner_roll_size; // Size of chunk to roll, in bytes 17 # define TEST_INNER_ROLL_MIN_NUM 1 18 # define TEST_INNER_ROLL_MAX_NUM 3 19 unsigned int inner_roll_num; // Number of times to roll 20 # define TEST_OUTER_ROLL_MIN_SIZE 2 21 # define TEST_OUTER_ROLL_MAX_SIZE 5 22 unsigned int outer_roll_size; // Size of section to roll, in chunks 23 # define TEST_OUTER_ROLL_MIN_NUM 1 24 # define TEST_OUTER_ROLL_MAX_NUM 3 25 unsigned int outer_roll_num; // Number of times to roll 26 27 char buffer[TEST_INNER_ROLL_MAX_SIZE * TEST_OUTER_ROLL_MAX_SIZE]; 28 29 TEST_roller_generator_t *generator; 30 TEST_roller_extractor_t *extractor; 31 TEST_roller_runner_t *runner; 32 }; 33 34 struct test_roller1_generator_data_t { 35 TEST_roller_t *obj; 36 unsigned int seed; 37 }; 38 39 static unsigned int reseed(unsigned int seed) 40 { 41 return (seed * 56473) % 91827; 42 } 43 44 static void generate(struct test_roller1_data_t *p, unsigned int seed) 45 { 46 seed = reseed(seed); 47 p->inner_roll_size 48 = (seed % (TEST_INNER_ROLL_MAX_SIZE - TEST_INNER_ROLL_MIN_SIZE + 1)) 49 + TEST_INNER_ROLL_MIN_SIZE; 50 seed = reseed(seed); 51 p->inner_roll_num 52 = (seed % (TEST_INNER_ROLL_MAX_NUM - TEST_INNER_ROLL_MIN_NUM + 1)) 53 + TEST_INNER_ROLL_MIN_NUM; 54 seed = reseed(seed); 55 p->outer_roll_size 56 = (seed % (TEST_OUTER_ROLL_MAX_SIZE - TEST_OUTER_ROLL_MIN_SIZE + 1)) 57 + TEST_OUTER_ROLL_MIN_SIZE; 58 seed = reseed(seed); 59 p->outer_roll_num 60 = (seed % (TEST_OUTER_ROLL_MAX_NUM - TEST_OUTER_ROLL_MIN_NUM + 1)) 61 + TEST_OUTER_ROLL_MIN_NUM; 62 } 63 64 static LE_STATUS roll(struct test_roller1_data_t *p, const char *input, 65 char *output, size_t output_sz) 66 { 67 size_t n = strlen(input); 68 size_t os = p->outer_roll_size; 69 size_t is = p->inner_roll_size; 70 if (n % (os * is) != 0) 71 return LE_STS_ERROR; 72 if (output_sz <= n) 73 return LE_STS_ERROR; 74 75 size_t on = p->outer_roll_num; 76 size_t in = p->inner_roll_num; 77 #ifdef TEST_OBJECT_DEBUG 78 fprintf(stderr, 79 "DEBUG[TEST_NR_roll]: " 80 "n = %zu, os = %zu, is = %zu, on = %zu, in = %zu\n", 81 n, os, is, on, in); 82 #endif 83 84 // i: Current input start index 85 // oi: Current input outer roll index 86 // ot: Current buffer outer roll index 87 // ii: Current input inner roll index 88 // it: Current buffer inner roll index 89 // pi: Current input position 90 // pb: Current buffer position 91 size_t i; 92 for (i = 0; i < n; i += os * is) { 93 for (size_t oi = 0; oi < os; oi++) { 94 size_t ot = (oi + on) % os; 95 for (size_t ii = 0; ii < is; ii++) { 96 size_t it = (ii + in) % is; 97 size_t pb = ot * is + it; 98 size_t pi = i + oi * is + ii; 99 char c = input[pi]; 100 #ifdef TEST_OBJECT_DEBUG 101 char cs[3] = { 0, 0, 0 }; 102 if (c) 103 cs[0] = c; 104 else 105 strcpy(cs, "\0"); 106 fprintf(stderr, 107 "DEBUG[TEST_NR_roll]: " 108 "i = %zu, oi = %zu, ot = %zu, ii = %zu, it = %zu, " 109 "buffer[%zu] = input[%zu] = '%s'\n", 110 i, oi, ot, ii, it, pb, pi, cs); 111 #endif 112 p->buffer[pb] = c; 113 } 114 } 115 for (size_t o = 0; o < os * is; o++) { 116 size_t po = i + o; 117 char c = p->buffer[o]; 118 #ifdef TEST_OBJECT_DEBUG 119 char cs[3] = { 0, 0, 0 }; 120 if (c) 121 cs[0] = c; 122 else 123 strcpy(cs, "\0"); 124 fprintf(stderr, "DEBUG[TEST_NR_roll]: output[%zu] = buffer[%zu] = '%s'\n", 125 po, o, cs); 126 #endif 127 output[po] = c; 128 } 129 } 130 #ifdef TEST_OBJECT_DEBUG 131 fprintf(stderr, "DEBUG[TEST_NR_roll]: output[%zu] = '\\0'\n", i); 132 #endif 133 output[i] = '\0'; 134 135 return LE_STS_SUCCESS; 136 } 137 138 static LE_STATUS test_roller1_generator_dispatch(TEST_roller_generator_t *op, 139 int num, ...) 140 { 141 LE_STATUS status = LE_STS_ERROR; // TODO: Set more precise status 142 va_list ap; 143 static const int cmds[] = { LSC_OBJECT_TYPE_GENERATOR_COMMANDS(roller), 0 }; 144 static const LSC_param_desc_t param_desc[] = { 145 { "seed", 1, 146 (LSC_data_desc_t){LSC_DT_unsigned_integer, 147 { { sizeof(unsigned int), sizeof(unsigned int) }, 148 { 0, 0 } } } }, 149 { NULL, } 150 }; 151 152 153 va_start(ap, num); 154 switch (num) { 155 LSC_OBJECT_GENERATOR_TYPE_DISPATCHES(roller, "roller1", op, status, ap, cmds); 156 case LSC_NR_get_settable_roller_generation_param_desc: 157 case LSC_NR_get_gettable_roller_generation_param_desc: 158 { 159 const LSC_param_desc_t **desc = va_arg(ap, const LSC_param_desc_t **); 160 *desc = param_desc; 161 } 162 status = LE_STS_SUCCESS; 163 break; 164 case LSC_NR_set_roller_generation_param: 165 case LSC_NR_get_roller_generation_param: 166 { 167 int param_num = va_arg(ap, int); 168 LSC_param_t *data = va_arg(ap, LSC_param_t *); 169 struct test_roller1_generator_data_t *gendata = op->lsc_data; 170 171 switch (param_num) { 172 case 1: 173 if (data->size == sizeof(unsigned int)) { 174 switch (num) { 175 case LSC_NR_set_roller_generation_param: 176 gendata->seed = *(unsigned int *)data->data; 177 break; 178 case LSC_NR_get_roller_generation_param: 179 if (data->data != NULL) 180 *(unsigned int *)data->data = gendata->seed; 181 if (data->len != NULL) 182 *data->len = sizeof(int); 183 break; 184 } 185 status = LE_STS_SUCCESS; 186 } 187 break; 188 } 189 190 data++; 191 if (data->data != NULL || data->len != NULL) 192 status = LE_STS_ERROR; 193 } 194 break; 195 case LSC_NR_generate_roller: 196 { 197 struct test_roller1_generator_data_t *gendata = op->lsc_data; 198 199 if (gendata == NULL || gendata->obj == NULL) 200 break; 201 202 unsigned int seed = gendata->seed; 203 struct test_roller1_data_t **p = 204 (struct test_roller1_data_t **)&gendata->obj->lsc_data; 205 206 if (*p == NULL && (*p = malloc(sizeof(*p))) == NULL) 207 break; 208 209 generate(*p, seed); 210 } 211 status = LE_STS_SUCCESS; 212 break; 213 default: 214 assert(("roller generator called with an unknown command number", 0)); 215 } 216 217 va_end(ap); 218 return status; 219 } 220 221 static LE_STATUS test_destroy_roller1_generator(TEST_roller_generator_t *op) 222 { 223 if (op != NULL) 224 free(op->lsc_data); 225 free(op); 226 return LE_STS_SUCCESS; 227 } 228 229 static LE_STATUS test_roller1_extractor_dispatch(TEST_roller_extractor_t *op, 230 int num, ...) 231 { 232 LE_STATUS status = LE_STS_ERROR; // TODO: Set more precise status 233 struct test_roller1_data_t *p 234 = ((TEST_roller_t *)op->lsc_data)->lsc_data; 235 va_list ap; 236 static const int cmds[] = { LSC_OBJECT_TYPE_EXTRACTOR_COMMANDS(roller), 0 }; 237 static const LSC_param_desc_t param_desc[] = { 238 { "inner-roll-size", 0, 239 (LSC_data_desc_t){LSC_DT_unsigned_integer, 240 { { sizeof(unsigned int), sizeof(unsigned int) }, 241 { 0, 0 } } } }, 242 { "inner-roll-num", 1, 243 (LSC_data_desc_t){LSC_DT_unsigned_integer, 244 { { sizeof(unsigned int), sizeof(unsigned int) }, 245 { 0, 0 } } } }, 246 { "outer-roll-size", 2, 247 (LSC_data_desc_t){LSC_DT_unsigned_integer, 248 { { sizeof(unsigned int), sizeof(unsigned int) }, 249 { 0, 0 } } } }, 250 { "outer-roll-num", 3, 251 (LSC_data_desc_t){LSC_DT_unsigned_integer, 252 { { sizeof(unsigned int), sizeof(unsigned int) }, 253 { 0, 0 } } } }, 254 { NULL, } 255 }; 256 257 va_start(ap, num); 258 switch (num) { 259 LSC_OBJECT_EXTRACTOR_TYPE_DISPATCHES(roller, "roller1", op, status, ap, cmds); 260 case LSC_NR_get_gettable_roller_extraction_param_desc: 261 { 262 const LSC_param_desc_t **desc = va_arg(ap, const LSC_param_desc_t **); 263 *desc = param_desc; 264 } 265 status = LE_STS_SUCCESS; 266 break; 267 case LSC_NR_get_roller_extraction_param: 268 { 269 int param_num = va_arg(ap, int); 270 LSC_param_t *data = va_arg(ap, LSC_param_t *); 271 unsigned int *outnum[] = { 272 &p->inner_roll_size, &p->inner_roll_num, 273 &p->outer_roll_size, &p->outer_roll_num 274 }; 275 276 if (param_num < 0 || param_num >= sizeof(outnum)) 277 break; 278 279 if (data->data != NULL) 280 *(unsigned int *)data->data = *outnum[param_num]; 281 if (data->len != NULL) 282 *data->len = sizeof(*outnum[param_num]); 283 284 data++; 285 if (data->data != NULL || data->len != NULL) 286 break; 287 } 288 status = LE_STS_SUCCESS; 289 break; 290 default: 291 assert(("roller extractor called with an unknown command number", 0)); 292 } 293 294 va_end(ap); 295 return status; 296 } 297 298 static LE_STATUS test_destroy_roller1_extractor(TEST_roller_extractor_t *op) 299 { 300 free(op); 301 return LE_STS_SUCCESS; 302 } 303 304 static LE_STATUS test_roller1_runner_dispatch(TEST_roller_runner_t *op, int num, 305 ...) 306 { 307 LE_STATUS status = LE_STS_ERROR; // TODO: Set more precise status 308 struct test_roller1_data_t *p 309 = ((TEST_roller_t *)op->lsc_data)->lsc_data; 310 va_list ap; 311 static const int cmds[] = { TEST_NR_run_roll, 0 }; 312 313 va_start(ap, num); 314 switch (num) { 315 LSC_OPERATION_TYPE_BASE_DISPATCHES(roller_runner, "roller1", r, status, ap, 316 cmds); 317 case TEST_NR_run_roll: 318 { 319 const char *input = va_arg(ap, const char *); 320 char *output = va_arg(ap, char *); 321 size_t output_sz = va_arg(ap, size_t); 322 323 if (p == NULL) 324 break; 325 326 status = roll(p, input, output, output_sz); 327 } 328 break; 329 } 330 331 va_end(ap); 332 return status; 333 } 334 335 static LE_STATUS test_destroy_roller1_runner(TEST_roller_runner_t *op) 336 { 337 free(op); 338 return LE_STS_SUCCESS; 339 } 340 341 static LE_STATUS test_roller1_dispatch(TEST_roller_t *r, int num, ...) 342 { 343 LE_STATUS status = LE_STS_ERROR; // TODO: Set more precise status 344 struct test_roller1_data_t **p 345 = ((struct test_roller1_data_t **)&r->lsc_data); 346 va_list ap; 347 static const int cmds[] = { LSC_NR_get_roller_generator, 348 LSC_NR_get_roller_extractor, 349 TEST_NR_get_roller_runner, 350 TEST_NR_roll, 0 }; 351 352 va_start(ap, num); 353 switch (num) { 354 LSC_OBJECT_TYPE_BASE_DISPATCHES(roller, "roller1", r, status, ap, cmds); 355 case LSC_NR_get_roller_generator: 356 { 357 TEST_roller_generator_t **op = va_arg(ap, TEST_roller_generator_t **); 358 359 if (*p == NULL && (*p = malloc(sizeof(**p))) == NULL) 360 break; 361 362 if ((*p)->generator == NULL) { 363 status = TEST_new_roller_generator(test_roller1_generator_dispatch, 364 test_destroy_roller1_generator, 365 NULL, &(*p)->generator); 366 } 367 if ((*p)->generator != NULL) { 368 struct test_roller1_generator_data_t **gendata 369 = (struct test_roller1_generator_data_t **)&(*p)->generator->lsc_data; 370 371 if (*gendata == NULL) 372 *gendata = malloc(sizeof(**gendata)); 373 if (*gendata == NULL) { 374 status = LE_STS_FATAL_ERROR; 375 break; 376 } 377 (*gendata)->obj = r; 378 (*op) = (*p)->generator; 379 } 380 } 381 break; 382 case LSC_NR_get_roller_extractor: 383 { 384 TEST_roller_extractor_t **op = va_arg(ap, TEST_roller_extractor_t **); 385 386 if (*p == NULL && (*p = malloc(sizeof(**p))) == NULL) 387 break; 388 389 if ((*p)->extractor == NULL) { 390 status = TEST_new_roller_extractor(test_roller1_extractor_dispatch, 391 test_destroy_roller1_extractor, 392 NULL, &(*p)->extractor); 393 } 394 if ((*p)->extractor != NULL) { 395 (*p)->extractor->lsc_data = r; 396 (*op) = (*p)->extractor; 397 } 398 } 399 break; 400 case TEST_NR_get_roller_runner: 401 { 402 TEST_roller_runner_t **op = va_arg(ap, TEST_roller_runner_t **); 403 404 if (*p == NULL && (*p = malloc(sizeof(**p))) == NULL) 405 break; 406 407 if ((*p)->runner == NULL) { 408 status = TEST_new_roller_runner(test_roller1_runner_dispatch, 409 test_destroy_roller1_runner, 410 NULL, &(*p)->runner); 411 } 412 if ((*p)->runner != NULL) { 413 (*p)->runner->lsc_data = r; 414 (*op) = (*p)->runner; 415 } 416 } 417 break; 418 case TEST_NR_roll: 419 { 420 const char *input = va_arg(ap, const char *); 421 char *output = va_arg(ap, char *); 422 size_t output_sz = va_arg(ap, size_t); 423 424 if (*p == NULL) 425 break; 426 427 status = roll(*p, input, output, output_sz); 428 } 429 break; 430 default: 431 assert(("roller called with an unknown command number", 0)); 432 } 433 434 va_end(ap); 435 return status; 436 } 437 438 static LE_STATUS test_destroy_roller1(TEST_roller_t *r) 439 { 440 LE_STATUS status = LE_STS_SUCCESS; 441 442 if (r != NULL) { 443 struct test_roller1_data_t *p 444 = (struct test_roller1_data_t *)r->lsc_data; 445 446 if (!LE_status_is_OK(status = TEST_free_roller_generator(p->generator))) 447 return status; 448 if (!LE_status_is_OK(status = TEST_free_roller_extractor(p->extractor))) 449 return status; 450 if (!LE_status_is_OK(status = TEST_free_roller_runner(p->runner))) 451 return status; 452 free(r->lsc_data); 453 } 454 free(r); 455 return LE_STS_SUCCESS; 456 } 457 458 static LE_STATUS TEST_new_roller1(TEST_roller_t **r) 459 { 460 return TEST_new_roller(test_roller1_dispatch, test_destroy_roller1, NULL, 461 r); 462 }