Changeset 5e718d9 in mainline for uspace/lib/bithenge/transform.c
- Timestamp:
- 2012-08-21T10:04:16Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 67edca6
- Parents:
- 0da6c04 (diff), 6a97f2e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/bithenge/transform.c
r0da6c04 r5e718d9 37 37 #include <assert.h> 38 38 #include <errno.h> 39 #include <stdarg.h> 39 40 #include <stdlib.h> 40 41 #include "blob.h" 42 #include "os.h" 43 #include "print.h" 41 44 #include "transform.h" 45 46 47 48 /***************** transform *****************/ 42 49 43 50 /** Initialize a new transform. … … 56 63 assert(ops->apply || ops->prefix_apply); 57 64 assert(ops->destroy); 65 if (bithenge_should_fail()) 66 return ENOMEM; 58 67 self->ops = ops; 59 68 self->refs = 1; … … 137 146 * @param[out] out_node Holds the result of applying this transform to the 138 147 * prefix. 139 * @param[out] out_size Holds the size of the prefix. 148 * @param[out] out_size Holds the size of the prefix. Can be null, in which 149 * case the size is not determined. 140 150 * @return EOK on success, ENOTSUP if not supported, or another error code from 141 151 * errno.h. */ … … 152 162 return ENOTSUP; 153 163 154 int rc = bithenge_transform_prefix_length(self, scope, blob, out_size); 164 aoff64_t size; 165 int rc = bithenge_transform_prefix_length(self, scope, blob, &size); 155 166 if (rc != EOK) 156 167 return rc; 157 168 bithenge_node_t *prefix_blob; 158 169 bithenge_blob_inc_ref(blob); 159 rc = bithenge_new_subblob(&prefix_blob, blob, 0, *out_size);170 rc = bithenge_new_subblob(&prefix_blob, blob, 0, size); 160 171 if (rc != EOK) 161 172 return rc; 162 173 rc = bithenge_transform_apply(self, scope, prefix_blob, out_node); 163 174 bithenge_node_dec_ref(prefix_blob); 175 if (out_size) 176 *out_size = size; 164 177 return rc; 165 178 } 179 180 181 182 /***************** scope *****************/ 166 183 167 184 /** Create a transform scope. It must be dereferenced with @a 168 185 * bithenge_scope_dec_ref after it is used. Takes ownership of nothing. 186 * @memberof bithenge_scope_t 169 187 * @param[out] out Holds the new scope. 170 188 * @param outer The outer scope, or NULL. … … 179 197 bithenge_scope_inc_ref(outer); 180 198 self->outer = outer; 199 self->error = NULL; 181 200 self->barrier = false; 182 201 self->num_params = 0; … … 189 208 190 209 /** Dereference a transform scope. 191 * @param self The scope to dereference. */ 210 * @memberof bithenge_scope_t 211 * @param self The scope to dereference, or NULL. */ 192 212 void bithenge_scope_dec_ref(bithenge_scope_t *self) 193 213 { … … 201 221 bithenge_scope_dec_ref(self->outer); 202 222 free(self->params); 223 free(self->error); 203 224 free(self); 204 225 } 205 226 206 227 /** Get the outer scope of a scope, which may be NULL. 228 * @memberof bithenge_scope_t 207 229 * @param self The scope to examine. 208 230 * @return The outer scope, which may be NULL. */ … … 212 234 } 213 235 236 /** Get the error message stored in the scope, which may be NULL. The error 237 * message only exists as long as the scope does. 238 * @memberof bithenge_scope_t 239 * @param scope The scope to get the error message from. 240 * @return The error message, or NULL. */ 241 const char *bithenge_scope_get_error(bithenge_scope_t *scope) 242 { 243 return scope->error; 244 } 245 246 /** Set the error message for the scope. The error message is stored in the 247 * outermost scope, but if any scope already has an error message this error 248 * message is ignored. 249 * @memberof bithenge_scope_t 250 * @param scope The scope. 251 * @param format The format string. 252 * @return EINVAL normally, or another error code from errno.h. */ 253 int bithenge_scope_error(bithenge_scope_t *scope, const char *format, ...) 254 { 255 if (scope->error) 256 return EINVAL; 257 while (scope->outer) { 258 scope = scope->outer; 259 if (scope->error) 260 return EINVAL; 261 } 262 size_t space_left = 256; 263 scope->error = malloc(space_left); 264 if (!scope->error) 265 return ENOMEM; 266 char *out = scope->error; 267 va_list ap; 268 va_start(ap, format); 269 270 while (*format) { 271 if (format[0] == '%' && format[1] == 't') { 272 format += 2; 273 int rc = bithenge_print_node_to_string(&out, 274 &space_left, BITHENGE_PRINT_PYTHON, 275 va_arg(ap, bithenge_node_t *)); 276 if (rc != EOK) { 277 va_end(ap); 278 return rc; 279 } 280 } else { 281 const char *end = str_chr(format, '%'); 282 if (!end) 283 end = format + str_length(format); 284 size_t size = min((size_t)(end - format), 285 space_left - 1); 286 memcpy(out, format, size); 287 format = end; 288 out += size; 289 space_left -= size; 290 } 291 } 292 *out = '\0'; 293 294 va_end(ap); 295 return EINVAL; 296 } 297 214 298 /** Get the current node being created, which may be NULL. 299 * @memberof bithenge_scope_t 215 300 * @param scope The scope to get the current node from. 216 301 * @return The node being created, or NULL. */ … … 223 308 224 309 /** Set the current node being created. Takes a reference to @a node. 310 * @memberof bithenge_scope_t 225 311 * @param scope The scope to set the current node in. 226 312 * @param node The current node being created, or NULL. */ … … 233 319 234 320 /** Get the current input node, which may be NULL. 321 * @memberof bithenge_scope_t 235 322 * @param scope The scope to get the current input node from. 236 323 * @return The input node, or NULL. */ … … 243 330 244 331 /** Set the current input node. Takes a reference to @a node. 332 * @memberof bithenge_scope_t 245 333 * @param scope The scope to set the input node in. 246 334 * @param node The input node, or NULL. */ … … 252 340 253 341 /** Set a scope as a barrier. 342 * @memberof bithenge_scope_t 254 343 * @param self The scope to change. */ 255 344 void bithenge_scope_set_barrier(bithenge_scope_t *self) … … 260 349 /** Check whether a scope is a barrier, meaning that variable lookup stops at 261 350 * it. 351 * @memberof bithenge_scope_t 262 352 * @param self The scope to check. 263 353 * @return Whether the scope is a barrier. */ … … 270 360 * bithenge_scope_set_param. This must not be called on a scope that already 271 361 * has parameters. 362 * @memberof bithenge_scope_t 272 363 * @param scope The scope in which to allocate parameters. 273 364 * @param num_params The number of parameters to allocate. … … 284 375 } 285 376 286 /** Set a parameter. Takes a reference to @a value. Note that range checking is377 /** Set a parameter. Takes a reference to @a node. Note that range checking is 287 378 * not done in release builds. 379 * @memberof bithenge_scope_t 288 380 * @param scope The scope in which to allocate parameters. 289 381 * @param i The index of the parameter to set. 290 * @param value The value to store in the parameter.382 * @param node The value to store in the parameter. 291 383 * @return EOK on success or an error code from errno.h. */ 292 384 int bithenge_scope_set_param( bithenge_scope_t *scope, int i, … … 295 387 assert(scope); 296 388 assert(i >= 0 && i < scope->num_params); 389 if (bithenge_should_fail()) { 390 bithenge_node_dec_ref(node); 391 return ENOMEM; 392 } 297 393 scope->params[i] = node; 298 394 return EOK; … … 300 396 301 397 /** Get a parameter. Note that range checking is not done in release builds. 398 * @memberof bithenge_scope_t 302 399 * @param scope The scope to get the parameter from. 303 400 * @param i The index of the parameter to set. … … 318 415 } 319 416 417 418 419 /***************** barrier_transform *****************/ 420 320 421 typedef struct { 321 422 bithenge_transform_t base; … … 344 445 return rc; 345 446 bithenge_scope_set_barrier(inner_scope); 346 rc = bithenge_transform_apply(self->transform, scope, in, out); 447 bithenge_scope_set_in_node(inner_scope, in); 448 rc = bithenge_transform_apply(self->transform, inner_scope, in, out); 347 449 bithenge_scope_dec_ref(inner_scope); 348 450 return rc; … … 358 460 return rc; 359 461 bithenge_scope_set_barrier(inner_scope); 360 rc = bithenge_transform_prefix_length(self->transform, scope, in, out); 462 bithenge_scope_set_in_node(inner_scope, bithenge_blob_as_node(in)); 463 rc = bithenge_transform_prefix_length(self->transform, inner_scope, in, 464 out); 361 465 bithenge_scope_dec_ref(inner_scope); 362 466 return rc; … … 373 477 return rc; 374 478 bithenge_scope_set_barrier(inner_scope); 375 rc = bithenge_transform_prefix_apply(self->transform, scope, in, 479 bithenge_scope_set_in_node(inner_scope, bithenge_blob_as_node(in)); 480 rc = bithenge_transform_prefix_apply(self->transform, inner_scope, in, 376 481 out_node, out_length); 377 482 bithenge_scope_dec_ref(inner_scope); … … 393 498 }; 394 499 500 /** Set the subtransform of a barrier transform. This must be done before the 501 * barrier transform is used. Takes a reference to @a transform. 502 * @param base The barrier transform. 503 * @param transform The subtransform to use for all operations. 504 * @return EOK on success or an error code from errno.h. */ 505 int bithenge_barrier_transform_set_subtransform(bithenge_transform_t *base, 506 bithenge_transform_t *transform) 507 { 508 assert(transform); 509 assert(bithenge_transform_num_params(transform) == 0); 510 511 if (bithenge_should_fail()) { 512 bithenge_transform_dec_ref(transform); 513 return ENOMEM; 514 } 515 516 barrier_transform_t *self = transform_as_barrier(base); 517 assert(!self->transform); 518 self->transform = transform; 519 return EOK; 520 } 521 395 522 /** Create a wrapper transform that creates a new scope. This ensures nothing 396 523 * from the outer scope is passed in, other than parameters. The wrapper may 397 * have a different value for num_params. T akes a reference to @a transform,398 * which it will use for all operations.524 * have a different value for num_params. The subtransform must be set with @a 525 * bithenge_barrier_transform_set_subtransform before the result is used. 399 526 * @param[out] out Holds the created transform. 400 * @param transform The transform to wrap.401 527 * @param num_params The number of parameters to require, which may be 0. 402 528 * @return EOK on success or an error code from errno.h. */ 403 int bithenge_new_barrier_transform(bithenge_transform_t **out, 404 bithenge_transform_t *transform, int num_params) 405 { 406 assert(transform); 407 assert(bithenge_transform_num_params(transform) == 0); 408 529 int bithenge_new_barrier_transform(bithenge_transform_t **out, int num_params) 530 { 409 531 int rc; 410 532 barrier_transform_t *self = malloc(sizeof(*self)); … … 417 539 if (rc != EOK) 418 540 goto error; 419 self->transform = transform;541 self->transform = NULL; 420 542 *out = barrier_as_transform(self); 421 543 return EOK; 422 544 error: 423 bithenge_transform_dec_ref(transform);424 545 free(self); 425 546 return rc; … … 480 601 { 481 602 char buffer; 482 *out_size = 1; 483 int rc = bithenge_blob_read_bits(blob, 0, &buffer, out_size, true); 484 if (rc != EOK) 485 return rc; 486 if (*out_size != 1) 487 return EINVAL; 603 aoff64_t size = 1; 604 int rc = bithenge_blob_read_bits(blob, 0, &buffer, &size, true); 605 if (rc != EOK) 606 return rc; 607 if (size != 1) 608 return EINVAL; 609 if (out_size) 610 *out_size = size; 488 611 return bithenge_new_boolean_node(out_node, (buffer & 1) != 0); 489 612 } … … 758 881 } 759 882 883 /** @cond internal */ 760 884 #define MAKE_UINT_TRANSFORM(NAME, TYPE, ENDIAN, PREFIX_LENGTH_FUNC) \ 761 885 static int NAME##_apply(bithenge_transform_t *self, \ … … 795 919 MAKE_UINT_TRANSFORM(uint32le, uint32_t, uint32_t_le2host, prefix_length_4); 796 920 MAKE_UINT_TRANSFORM(uint32be, uint32_t, uint32_t_be2host, prefix_length_4); 797 MAKE_UINT_TRANSFORM(uint64le, uint64_t, uint32_t_le2host, prefix_length_8); 798 MAKE_UINT_TRANSFORM(uint64be, uint64_t, uint32_t_be2host, prefix_length_8); 921 MAKE_UINT_TRANSFORM(uint64le, uint64_t, uint64_t_le2host, prefix_length_8); 922 MAKE_UINT_TRANSFORM(uint64be, uint64_t, uint64_t_be2host, prefix_length_8); 923 /** @endcond */ 799 924 800 925 … … 822 947 return EINVAL; 823 948 824 *out_size = num_bits;949 aoff64_t size = num_bits; 825 950 uint8_t buffer[sizeof(bithenge_int_t)]; 826 rc = bithenge_blob_read_bits(blob, 0, (char *)buffer, out_size,951 rc = bithenge_blob_read_bits(blob, 0, (char *)buffer, &size, 827 952 little_endian); 828 953 if (rc != EOK) 829 954 return rc; 830 if (*out_size != (aoff64_t)num_bits) 831 return EINVAL; 955 if (size != (aoff64_t)num_bits) 956 return EINVAL; 957 if (out_size) 958 *out_size = size; 832 959 833 960 bithenge_int_t result = 0; … … 948 1075 bithenge_named_transform_t *bithenge_primitive_transforms = primitive_transforms; 949 1076 950 typedef struct {951 bithenge_transform_t base;952 bithenge_transform_t **xforms;953 size_t num;954 } compose_transform_t;955 956 static bithenge_transform_t *compose_as_transform(compose_transform_t *xform)957 {958 return &xform->base;959 }960 961 static compose_transform_t *transform_as_compose(bithenge_transform_t *xform)962 {963 return (compose_transform_t *)xform;964 }965 966 static int compose_apply(bithenge_transform_t *base, bithenge_scope_t *scope,967 bithenge_node_t *in, bithenge_node_t **out)968 {969 int rc;970 compose_transform_t *self = transform_as_compose(base);971 bithenge_node_inc_ref(in);972 973 /* i ranges from (self->num - 1) to 0 inside the loop. */974 for (size_t i = self->num; i--; ) {975 bithenge_node_t *tmp;976 rc = bithenge_transform_apply(self->xforms[i], scope, in,977 &tmp);978 bithenge_node_dec_ref(in);979 if (rc != EOK)980 return rc;981 in = tmp;982 }983 984 *out = in;985 return rc;986 }987 988 static int compose_prefix_length(bithenge_transform_t *base,989 bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)990 {991 compose_transform_t *self = transform_as_compose(base);992 return bithenge_transform_prefix_length(self->xforms[self->num - 1],993 scope, blob, out);994 }995 996 static void compose_destroy(bithenge_transform_t *base)997 {998 compose_transform_t *self = transform_as_compose(base);999 for (size_t i = 0; i < self->num; i++)1000 bithenge_transform_dec_ref(self->xforms[i]);1001 free(self->xforms);1002 free(self);1003 }1004 1005 static const bithenge_transform_ops_t compose_transform_ops = {1006 .apply = compose_apply,1007 .prefix_length = compose_prefix_length,1008 .destroy = compose_destroy,1009 };1010 1011 /** Create a composition of multiple transforms. When the result is applied to a1012 * node, each transform is applied in turn, with the last transform applied1013 * first. @a xforms may contain any number of transforms or no transforms at1014 * all. This function takes ownership of @a xforms and the references therein.1015 * @param[out] out Holds the result.1016 * @param[in] xforms The transforms to apply.1017 * @param num The number of transforms.1018 * @return EOK on success or an error code from errno.h. */1019 int bithenge_new_composed_transform(bithenge_transform_t **out,1020 bithenge_transform_t **xforms, size_t num)1021 {1022 if (num == 0) {1023 /* TODO: optimize */1024 } else if (num == 1) {1025 *out = xforms[0];1026 free(xforms);1027 return EOK;1028 }1029 1030 int rc;1031 compose_transform_t *self = malloc(sizeof(*self));1032 if (!self) {1033 rc = ENOMEM;1034 goto error;1035 }1036 rc = bithenge_init_transform(compose_as_transform(self),1037 &compose_transform_ops, 0);1038 if (rc != EOK)1039 goto error;1040 self->xforms = xforms;1041 self->num = num;1042 *out = compose_as_transform(self);1043 return EOK;1044 error:1045 for (size_t i = 0; i < num; i++)1046 bithenge_transform_dec_ref(xforms[i]);1047 free(xforms);1048 free(self);1049 return rc;1050 }1051 1052 1077 /** @} 1053 1078 */
Note:
See TracChangeset
for help on using the changeset viewer.