diff options
author | Ron Yorston <rmy@pobox.com> | 2019-02-12 08:43:06 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2019-02-12 08:43:06 +0000 |
commit | 7a8bd5ae33d8c390763f0787afe6b8c495e2d978 (patch) | |
tree | 29b0abb320d73b37f4fa4d9b355b3b32db42e836 /miscutils | |
parent | 0eda390d68c456975289471e68b615ae096ab33b (diff) | |
parent | f81e0120f4478c58e126bcadb19b9954ed184e8f (diff) | |
download | busybox-w32-7a8bd5ae33d8c390763f0787afe6b8c495e2d978.tar.gz busybox-w32-7a8bd5ae33d8c390763f0787afe6b8c495e2d978.tar.bz2 busybox-w32-7a8bd5ae33d8c390763f0787afe6b8c495e2d978.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'miscutils')
-rw-r--r-- | miscutils/bc.c | 271 | ||||
-rw-r--r-- | miscutils/i2c_tools.c | 176 |
2 files changed, 360 insertions, 87 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index 7fecb264d..36e978ed8 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
@@ -4,8 +4,8 @@ | |||
4 | * Adapted from https://github.com/gavinhoward/bc | 4 | * Adapted from https://github.com/gavinhoward/bc |
5 | * Original code copyright (c) 2018 Gavin D. Howard and contributors. | 5 | * Original code copyright (c) 2018 Gavin D. Howard and contributors. |
6 | */ | 6 | */ |
7 | //TODO: GNU extensions: | 7 | //TODO: |
8 | // support "define f(*param[])" - "pass array by reference" syntax | 8 | // maybe implement a^b for non-integer b? |
9 | 9 | ||
10 | #define DEBUG_LEXER 0 | 10 | #define DEBUG_LEXER 0 |
11 | #define DEBUG_COMPILE 0 | 11 | #define DEBUG_COMPILE 0 |
@@ -380,6 +380,12 @@ typedef struct BcInstPtr { | |||
380 | size_t inst_idx; | 380 | size_t inst_idx; |
381 | } BcInstPtr; | 381 | } BcInstPtr; |
382 | 382 | ||
383 | typedef enum BcType { | ||
384 | BC_TYPE_VAR, | ||
385 | BC_TYPE_ARRAY, | ||
386 | BC_TYPE_REF, | ||
387 | } BcType; | ||
388 | |||
383 | typedef enum BcLexType { | 389 | typedef enum BcLexType { |
384 | XC_LEX_EOF, | 390 | XC_LEX_EOF, |
385 | XC_LEX_INVALID, | 391 | XC_LEX_INVALID, |
@@ -1092,15 +1098,25 @@ static void bc_vec_pop_all(BcVec *v) | |||
1092 | bc_vec_npop(v, v->len); | 1098 | bc_vec_npop(v, v->len); |
1093 | } | 1099 | } |
1094 | 1100 | ||
1095 | static size_t bc_vec_push(BcVec *v, const void *data) | 1101 | static size_t bc_vec_npush(BcVec *v, size_t n, const void *data) |
1096 | { | 1102 | { |
1097 | size_t len = v->len; | 1103 | size_t len = v->len; |
1098 | if (len >= v->cap) bc_vec_grow(v, 1); | 1104 | if (len + n > v->cap) bc_vec_grow(v, n); |
1099 | memmove(v->v + (v->size * len), data, v->size); | 1105 | memmove(v->v + (v->size * len), data, v->size * n); |
1100 | v->len++; | 1106 | v->len = len + n; |
1101 | return len; | 1107 | return len; |
1102 | } | 1108 | } |
1103 | 1109 | ||
1110 | static size_t bc_vec_push(BcVec *v, const void *data) | ||
1111 | { | ||
1112 | return bc_vec_npush(v, 1, data); | ||
1113 | //size_t len = v->len; | ||
1114 | //if (len >= v->cap) bc_vec_grow(v, 1); | ||
1115 | //memmove(v->v + (v->size * len), data, v->size); | ||
1116 | //v->len = len + 1; | ||
1117 | //return len; | ||
1118 | } | ||
1119 | |||
1104 | // G.prog.results often needs "pop old operand, push result" idiom. | 1120 | // G.prog.results often needs "pop old operand, push result" idiom. |
1105 | // Can do this without a few extra ops | 1121 | // Can do this without a few extra ops |
1106 | static size_t bc_result_pop_and_push(const void *data) | 1122 | static size_t bc_result_pop_and_push(const void *data) |
@@ -3528,14 +3544,14 @@ static void xc_parse_pushName(char *name) | |||
3528 | // (The above describes 32-bit case). | 3544 | // (The above describes 32-bit case). |
3529 | #define SMALL_INDEX_LIMIT (0x100 - sizeof(size_t)) | 3545 | #define SMALL_INDEX_LIMIT (0x100 - sizeof(size_t)) |
3530 | 3546 | ||
3531 | static void xc_parse_pushIndex(size_t idx) | 3547 | static void bc_vec_pushIndex(BcVec *v, size_t idx) |
3532 | { | 3548 | { |
3533 | size_t mask; | 3549 | size_t mask; |
3534 | unsigned amt; | 3550 | unsigned amt; |
3535 | 3551 | ||
3536 | dbg_lex("%s:%d pushing index %zd", __func__, __LINE__, idx); | 3552 | dbg_lex("%s:%d pushing index %zd", __func__, __LINE__, idx); |
3537 | if (idx < SMALL_INDEX_LIMIT) { | 3553 | if (idx < SMALL_INDEX_LIMIT) { |
3538 | xc_parse_push(idx); | 3554 | bc_vec_pushByte(v, idx); |
3539 | return; | 3555 | return; |
3540 | } | 3556 | } |
3541 | 3557 | ||
@@ -3548,14 +3564,19 @@ static void xc_parse_pushIndex(size_t idx) | |||
3548 | } | 3564 | } |
3549 | // amt is at least 1 here - "one byte of length data follows" | 3565 | // amt is at least 1 here - "one byte of length data follows" |
3550 | 3566 | ||
3551 | xc_parse_push((SMALL_INDEX_LIMIT - 1) + amt); | 3567 | bc_vec_pushByte(v, (SMALL_INDEX_LIMIT - 1) + amt); |
3552 | 3568 | ||
3553 | do { | 3569 | do { |
3554 | xc_parse_push((unsigned char)idx); | 3570 | bc_vec_pushByte(v, (unsigned char)idx); |
3555 | idx >>= 8; | 3571 | idx >>= 8; |
3556 | } while (idx != 0); | 3572 | } while (idx != 0); |
3557 | } | 3573 | } |
3558 | 3574 | ||
3575 | static void xc_parse_pushIndex(size_t idx) | ||
3576 | { | ||
3577 | bc_vec_pushIndex(&G.prs.func->code, idx); | ||
3578 | } | ||
3579 | |||
3559 | static void xc_parse_pushInst_and_Index(unsigned inst, size_t idx) | 3580 | static void xc_parse_pushInst_and_Index(unsigned inst, size_t idx) |
3560 | { | 3581 | { |
3561 | xc_parse_push(inst); | 3582 | xc_parse_push(inst); |
@@ -4340,7 +4361,7 @@ static BC_STATUS zbc_parse_break_or_continue(BcLexType type) | |||
4340 | } | 4361 | } |
4341 | #define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__) COMMA_SUCCESS) | 4362 | #define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__) COMMA_SUCCESS) |
4342 | 4363 | ||
4343 | static BC_STATUS zbc_func_insert(BcFunc *f, char *name, bool var) | 4364 | static BC_STATUS zbc_func_insert(BcFunc *f, char *name, BcType type) |
4344 | { | 4365 | { |
4345 | BcId *autoid; | 4366 | BcId *autoid; |
4346 | BcId a; | 4367 | BcId a; |
@@ -4349,13 +4370,13 @@ static BC_STATUS zbc_func_insert(BcFunc *f, char *name, bool var) | |||
4349 | autoid = (void*)f->autos.v; | 4370 | autoid = (void*)f->autos.v; |
4350 | for (i = 0; i < f->autos.len; i++, autoid++) { | 4371 | for (i = 0; i < f->autos.len; i++, autoid++) { |
4351 | if (strcmp(name, autoid->name) == 0 | 4372 | if (strcmp(name, autoid->name) == 0 |
4352 | && var == autoid->idx | 4373 | && type == (BcType) autoid->idx |
4353 | ) { | 4374 | ) { |
4354 | RETURN_STATUS(bc_error("duplicate function parameter or auto name")); | 4375 | RETURN_STATUS(bc_error("duplicate function parameter or auto name")); |
4355 | } | 4376 | } |
4356 | } | 4377 | } |
4357 | 4378 | ||
4358 | a.idx = var; | 4379 | a.idx = type; |
4359 | a.name = name; | 4380 | a.name = name; |
4360 | 4381 | ||
4361 | bc_vec_push(&f->autos, &a); | 4382 | bc_vec_push(&f->autos, &a); |
@@ -4368,7 +4389,7 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4368 | { | 4389 | { |
4369 | BcParse *p = &G.prs; | 4390 | BcParse *p = &G.prs; |
4370 | BcStatus s; | 4391 | BcStatus s; |
4371 | bool var, comma, voidfunc; | 4392 | bool comma, voidfunc; |
4372 | char *name; | 4393 | char *name; |
4373 | 4394 | ||
4374 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); | 4395 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); |
@@ -4406,6 +4427,16 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4406 | 4427 | ||
4407 | comma = false; | 4428 | comma = false; |
4408 | while (p->lex != BC_LEX_RPAREN) { | 4429 | while (p->lex != BC_LEX_RPAREN) { |
4430 | BcType t = BC_TYPE_VAR; | ||
4431 | |||
4432 | if (p->lex == XC_LEX_OP_MULTIPLY) { | ||
4433 | t = BC_TYPE_REF; | ||
4434 | s = zxc_lex_next(); | ||
4435 | if (s) RETURN_STATUS(s); | ||
4436 | s = zbc_POSIX_does_not_allow("references"); | ||
4437 | if (s) RETURN_STATUS(s); | ||
4438 | } | ||
4439 | |||
4409 | if (p->lex != XC_LEX_NAME) | 4440 | if (p->lex != XC_LEX_NAME) |
4410 | RETURN_STATUS(bc_error_bad_function_definition()); | 4441 | RETURN_STATUS(bc_error_bad_function_definition()); |
4411 | 4442 | ||
@@ -4415,9 +4446,8 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4415 | s = zxc_lex_next(); | 4446 | s = zxc_lex_next(); |
4416 | if (s) goto err; | 4447 | if (s) goto err; |
4417 | 4448 | ||
4418 | var = p->lex != BC_LEX_LBRACKET; | 4449 | if (p->lex == BC_LEX_LBRACKET) { |
4419 | 4450 | if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY; | |
4420 | if (!var) { | ||
4421 | s = zxc_lex_next(); | 4451 | s = zxc_lex_next(); |
4422 | if (s) goto err; | 4452 | if (s) goto err; |
4423 | 4453 | ||
@@ -4429,6 +4459,10 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4429 | s = zxc_lex_next(); | 4459 | s = zxc_lex_next(); |
4430 | if (s) goto err; | 4460 | if (s) goto err; |
4431 | } | 4461 | } |
4462 | else if (t == BC_TYPE_REF) { | ||
4463 | s = bc_error_at("vars can't be references"); | ||
4464 | goto err; | ||
4465 | } | ||
4432 | 4466 | ||
4433 | comma = p->lex == BC_LEX_COMMA; | 4467 | comma = p->lex == BC_LEX_COMMA; |
4434 | if (comma) { | 4468 | if (comma) { |
@@ -4436,7 +4470,7 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4436 | if (s) goto err; | 4470 | if (s) goto err; |
4437 | } | 4471 | } |
4438 | 4472 | ||
4439 | s = zbc_func_insert(p->func, name, var); | 4473 | s = zbc_func_insert(p->func, name, t); |
4440 | if (s) goto err; | 4474 | if (s) goto err; |
4441 | } | 4475 | } |
4442 | 4476 | ||
@@ -4488,7 +4522,7 @@ static BC_STATUS zbc_parse_auto(void) | |||
4488 | if (s) RETURN_STATUS(s); | 4522 | if (s) RETURN_STATUS(s); |
4489 | 4523 | ||
4490 | for (;;) { | 4524 | for (;;) { |
4491 | bool var; | 4525 | BcType t; |
4492 | 4526 | ||
4493 | if (p->lex != XC_LEX_NAME) | 4527 | if (p->lex != XC_LEX_NAME) |
4494 | RETURN_STATUS(bc_error_at("bad 'auto' syntax")); | 4528 | RETURN_STATUS(bc_error_at("bad 'auto' syntax")); |
@@ -4497,8 +4531,9 @@ static BC_STATUS zbc_parse_auto(void) | |||
4497 | s = zxc_lex_next(); | 4531 | s = zxc_lex_next(); |
4498 | if (s) goto err; | 4532 | if (s) goto err; |
4499 | 4533 | ||
4500 | var = (p->lex != BC_LEX_LBRACKET); | 4534 | t = BC_TYPE_VAR; |
4501 | if (!var) { | 4535 | if (p->lex == BC_LEX_LBRACKET) { |
4536 | t = BC_TYPE_ARRAY; | ||
4502 | s = zxc_lex_next(); | 4537 | s = zxc_lex_next(); |
4503 | if (s) goto err; | 4538 | if (s) goto err; |
4504 | 4539 | ||
@@ -4510,7 +4545,7 @@ static BC_STATUS zbc_parse_auto(void) | |||
4510 | if (s) goto err; | 4545 | if (s) goto err; |
4511 | } | 4546 | } |
4512 | 4547 | ||
4513 | s = zbc_func_insert(p->func, name, var); | 4548 | s = zbc_func_insert(p->func, name, t); |
4514 | if (s) goto err; | 4549 | if (s) goto err; |
4515 | 4550 | ||
4516 | if (p->lex == XC_LEX_NLINE | 4551 | if (p->lex == XC_LEX_NLINE |
@@ -5119,12 +5154,64 @@ static BC_STATUS zdc_parse_exprs_until_eof(void) | |||
5119 | #define STACK_HAS_MORE_THAN(s, n) ((s)->len > ((size_t)(n))) | 5154 | #define STACK_HAS_MORE_THAN(s, n) ((s)->len > ((size_t)(n))) |
5120 | #define STACK_HAS_EQUAL_OR_MORE_THAN(s, n) ((s)->len >= ((size_t)(n))) | 5155 | #define STACK_HAS_EQUAL_OR_MORE_THAN(s, n) ((s)->len >= ((size_t)(n))) |
5121 | 5156 | ||
5122 | static BcVec* xc_program_search(char *id, bool var) | 5157 | static size_t xc_program_index(char *code, size_t *bgn) |
5158 | { | ||
5159 | unsigned char *bytes = (void*)(code + *bgn); | ||
5160 | unsigned amt; | ||
5161 | unsigned i; | ||
5162 | size_t res; | ||
5163 | |||
5164 | amt = *bytes++; | ||
5165 | if (amt < SMALL_INDEX_LIMIT) { | ||
5166 | *bgn += 1; | ||
5167 | return amt; | ||
5168 | } | ||
5169 | amt -= (SMALL_INDEX_LIMIT - 1); // amt is 1 or more here | ||
5170 | *bgn += amt + 1; | ||
5171 | |||
5172 | res = 0; | ||
5173 | i = 0; | ||
5174 | do { | ||
5175 | res |= (size_t)(*bytes++) << i; | ||
5176 | i += 8; | ||
5177 | } while (--amt != 0); | ||
5178 | |||
5179 | return res; | ||
5180 | } | ||
5181 | |||
5182 | static char *xc_program_name(char *code, size_t *bgn) | ||
5183 | { | ||
5184 | code += *bgn; | ||
5185 | *bgn += strlen(code) + 1; | ||
5186 | |||
5187 | return xstrdup(code); | ||
5188 | } | ||
5189 | |||
5190 | static BcVec* xc_program_dereference(BcVec *vec) | ||
5191 | { | ||
5192 | BcVec *v; | ||
5193 | size_t vidx, nidx, i = 0; | ||
5194 | |||
5195 | //assert(vec->size == sizeof(uint8_t)); | ||
5196 | |||
5197 | vidx = xc_program_index(vec->v, &i); | ||
5198 | nidx = xc_program_index(vec->v, &i); | ||
5199 | |||
5200 | v = bc_vec_item(&G.prog.arrs, vidx); | ||
5201 | v = bc_vec_item(v, nidx); | ||
5202 | |||
5203 | //assert(v->size != sizeof(uint8_t)); | ||
5204 | |||
5205 | return v; | ||
5206 | } | ||
5207 | |||
5208 | static BcVec* xc_program_search(char *id, BcType type) | ||
5123 | { | 5209 | { |
5124 | BcId e, *ptr; | 5210 | BcId e, *ptr; |
5125 | BcVec *v, *map; | 5211 | BcVec *v, *map; |
5126 | size_t i; | 5212 | size_t i; |
5127 | int new; | 5213 | int new; |
5214 | bool var = (type == BC_TYPE_VAR); | ||
5128 | 5215 | ||
5129 | v = var ? &G.prog.vars : &G.prog.arrs; | 5216 | v = var ? &G.prog.vars : &G.prog.arrs; |
5130 | map = var ? &G.prog.var_map : &G.prog.arr_map; | 5217 | map = var ? &G.prog.var_map : &G.prog.arr_map; |
@@ -5178,17 +5265,20 @@ static BC_STATUS zxc_program_num(BcResult *r, BcNum **num) | |||
5178 | case XC_RESULT_VAR: | 5265 | case XC_RESULT_VAR: |
5179 | case XC_RESULT_ARRAY: | 5266 | case XC_RESULT_ARRAY: |
5180 | case XC_RESULT_ARRAY_ELEM: { | 5267 | case XC_RESULT_ARRAY_ELEM: { |
5181 | BcVec *v; | 5268 | BcType type = (r->t == XC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY; |
5182 | void *p; | 5269 | BcVec *v = xc_program_search(r->d.id.name, type); |
5183 | v = xc_program_search(r->d.id.name, r->t == XC_RESULT_VAR); | 5270 | void *p = bc_vec_top(v); |
5184 | // dc variables are all stacks, so here we have this: | 5271 | |
5185 | p = bc_vec_top(v); | ||
5186 | // TODO: eliminate these stacks for bc-only config? | ||
5187 | if (r->t == XC_RESULT_ARRAY_ELEM) { | 5272 | if (r->t == XC_RESULT_ARRAY_ELEM) { |
5273 | size_t idx = r->d.id.idx; | ||
5274 | |||
5188 | v = p; | 5275 | v = p; |
5189 | if (v->len <= r->d.id.idx) | 5276 | if (v->size == sizeof(uint8_t)) |
5190 | bc_array_expand(v, r->d.id.idx + 1); | 5277 | v = xc_program_dereference(v); |
5191 | *num = bc_vec_item(v, r->d.id.idx); | 5278 | //assert(v->size == sizeof(BcNum)); |
5279 | if (v->len <= idx) | ||
5280 | bc_array_expand(v, idx + 1); | ||
5281 | *num = bc_vec_item(v, idx); | ||
5192 | } else { | 5282 | } else { |
5193 | *num = p; | 5283 | *num = p; |
5194 | } | 5284 | } |
@@ -5347,39 +5437,6 @@ static BC_STATUS zxc_program_read(void) | |||
5347 | } | 5437 | } |
5348 | #define zxc_program_read(...) (zxc_program_read(__VA_ARGS__) COMMA_SUCCESS) | 5438 | #define zxc_program_read(...) (zxc_program_read(__VA_ARGS__) COMMA_SUCCESS) |
5349 | 5439 | ||
5350 | static size_t xc_program_index(char *code, size_t *bgn) | ||
5351 | { | ||
5352 | unsigned char *bytes = (void*)(code + *bgn); | ||
5353 | unsigned amt; | ||
5354 | unsigned i; | ||
5355 | size_t res; | ||
5356 | |||
5357 | amt = *bytes++; | ||
5358 | if (amt < SMALL_INDEX_LIMIT) { | ||
5359 | *bgn += 1; | ||
5360 | return amt; | ||
5361 | } | ||
5362 | amt -= (SMALL_INDEX_LIMIT - 1); // amt is 1 or more here | ||
5363 | *bgn += amt + 1; | ||
5364 | |||
5365 | res = 0; | ||
5366 | i = 0; | ||
5367 | do { | ||
5368 | res |= (size_t)(*bytes++) << i; | ||
5369 | i += 8; | ||
5370 | } while (--amt != 0); | ||
5371 | |||
5372 | return res; | ||
5373 | } | ||
5374 | |||
5375 | static char *xc_program_name(char *code, size_t *bgn) | ||
5376 | { | ||
5377 | code += *bgn; | ||
5378 | *bgn += strlen(code) + 1; | ||
5379 | |||
5380 | return xstrdup(code); | ||
5381 | } | ||
5382 | |||
5383 | static void xc_program_printString(const char *str) | 5440 | static void xc_program_printString(const char *str) |
5384 | { | 5441 | { |
5385 | #if ENABLE_DC | 5442 | #if ENABLE_DC |
@@ -5755,43 +5812,81 @@ static BC_STATUS zdc_program_assignStr(BcResult *r, BcVec *v, bool push) | |||
5755 | #define zdc_program_assignStr(...) (zdc_program_assignStr(__VA_ARGS__) COMMA_SUCCESS) | 5812 | #define zdc_program_assignStr(...) (zdc_program_assignStr(__VA_ARGS__) COMMA_SUCCESS) |
5756 | #endif // ENABLE_DC | 5813 | #endif // ENABLE_DC |
5757 | 5814 | ||
5758 | static BC_STATUS zxc_program_popResultAndCopyToVar(char *name, bool var) | 5815 | static BC_STATUS zxc_program_popResultAndCopyToVar(char *name, BcType t) |
5759 | { | 5816 | { |
5760 | BcStatus s; | 5817 | BcStatus s; |
5761 | BcResult *ptr, r; | 5818 | BcResult *ptr, r; |
5762 | BcVec *v; | 5819 | BcVec *vec; |
5763 | BcNum *n; | 5820 | BcNum *n; |
5821 | bool var = (t == BC_TYPE_VAR); | ||
5764 | 5822 | ||
5765 | if (!STACK_HAS_MORE_THAN(&G.prog.results, 0)) | 5823 | if (!STACK_HAS_MORE_THAN(&G.prog.results, 0)) |
5766 | RETURN_STATUS(bc_error_stack_has_too_few_elements()); | 5824 | RETURN_STATUS(bc_error_stack_has_too_few_elements()); |
5767 | 5825 | ||
5768 | ptr = bc_vec_top(&G.prog.results); | 5826 | ptr = bc_vec_top(&G.prog.results); |
5769 | if ((ptr->t == XC_RESULT_ARRAY) != !var) | 5827 | if ((ptr->t == XC_RESULT_ARRAY) == var) |
5770 | RETURN_STATUS(bc_error_variable_is_wrong_type()); | 5828 | RETURN_STATUS(bc_error_variable_is_wrong_type()); |
5771 | v = xc_program_search(name, var); | 5829 | vec = xc_program_search(name, t); |
5772 | 5830 | ||
5773 | #if ENABLE_DC | 5831 | #if ENABLE_DC |
5774 | if (ptr->t == XC_RESULT_STR && !var) | 5832 | if (ptr->t == XC_RESULT_STR) { |
5775 | RETURN_STATUS(bc_error_variable_is_wrong_type()); | 5833 | if (!var) |
5776 | if (ptr->t == XC_RESULT_STR) | 5834 | RETURN_STATUS(bc_error_variable_is_wrong_type()); |
5777 | RETURN_STATUS(zdc_program_assignStr(ptr, v, true)); | 5835 | RETURN_STATUS(zdc_program_assignStr(ptr, vec, true)); |
5836 | } | ||
5778 | #endif | 5837 | #endif |
5779 | 5838 | ||
5780 | s = zxc_program_num(ptr, &n); | 5839 | s = zxc_program_num(ptr, &n); |
5781 | if (s) RETURN_STATUS(s); | 5840 | if (s) RETURN_STATUS(s); |
5782 | 5841 | ||
5783 | // Do this once more to make sure that pointers were not invalidated. | 5842 | // Do this once more to make sure that pointers were not invalidated. |
5784 | v = xc_program_search(name, var); | 5843 | vec = xc_program_search(name, t); |
5785 | 5844 | ||
5786 | if (var) { | 5845 | if (var) { |
5787 | bc_num_init_DEF_SIZE(&r.d.n); | 5846 | bc_num_init_DEF_SIZE(&r.d.n); |
5788 | bc_num_copy(&r.d.n, n); | 5847 | bc_num_copy(&r.d.n, n); |
5789 | } else { | 5848 | } else { |
5849 | BcVec *v = (BcVec*) n; | ||
5850 | bool ref, ref_size; | ||
5851 | |||
5852 | ref = (v->size == sizeof(BcVec) && t != BC_TYPE_ARRAY); | ||
5853 | ref_size = (v->size == sizeof(uint8_t)); | ||
5854 | |||
5855 | if (ref || (ref_size && t == BC_TYPE_REF)) { | ||
5856 | bc_vec_init(&r.d.v, sizeof(uint8_t), NULL); | ||
5857 | if (ref) { | ||
5858 | size_t vidx, idx; | ||
5859 | BcId id; | ||
5860 | |||
5861 | id.name = ptr->d.id.name; | ||
5862 | v = xc_program_search(ptr->d.id.name, BC_TYPE_REF); | ||
5863 | |||
5864 | // Make sure the pointer was not invalidated. | ||
5865 | vec = xc_program_search(name, t); | ||
5866 | |||
5867 | vidx = bc_map_find_exact(&G.prog.arr_map, &id); | ||
5868 | //assert(vidx != BC_VEC_INVALID_IDX); | ||
5869 | vidx = ((BcId*) bc_vec_item(&G.prog.arr_map, vidx))->idx; | ||
5870 | idx = v->len - 1; | ||
5871 | |||
5872 | bc_vec_pushIndex(&r.d.v, vidx); | ||
5873 | bc_vec_pushIndex(&r.d.v, idx); | ||
5874 | } | ||
5875 | // If we get here, we are copying a ref to a ref. | ||
5876 | else bc_vec_npush(&r.d.v, v->len, v->v); | ||
5877 | |||
5878 | // We need to return early. | ||
5879 | goto ret; | ||
5880 | } | ||
5881 | |||
5882 | if (ref_size && t != BC_TYPE_REF) | ||
5883 | v = xc_program_dereference(v); | ||
5884 | |||
5790 | bc_array_init(&r.d.v, true); | 5885 | bc_array_init(&r.d.v, true); |
5791 | bc_array_copy(&r.d.v, (BcVec *) n); | 5886 | bc_array_copy(&r.d.v, v); |
5792 | } | 5887 | } |
5793 | 5888 | ret: | |
5794 | bc_vec_push(v, &r.d); | 5889 | bc_vec_push(vec, &r.d); |
5795 | bc_vec_pop(&G.prog.results); | 5890 | bc_vec_pop(&G.prog.results); |
5796 | 5891 | ||
5797 | RETURN_STATUS(s); | 5892 | RETURN_STATUS(s); |
@@ -5818,7 +5913,7 @@ static BC_STATUS zxc_program_assign(char inst) | |||
5818 | 5913 | ||
5819 | if (left->t != XC_RESULT_VAR) | 5914 | if (left->t != XC_RESULT_VAR) |
5820 | RETURN_STATUS(bc_error_variable_is_wrong_type()); | 5915 | RETURN_STATUS(bc_error_variable_is_wrong_type()); |
5821 | v = xc_program_search(left->d.id.name, true); | 5916 | v = xc_program_search(left->d.id.name, BC_TYPE_VAR); |
5822 | 5917 | ||
5823 | RETURN_STATUS(zdc_program_assignStr(right, v, false)); | 5918 | RETURN_STATUS(zdc_program_assignStr(right, v, false)); |
5824 | } | 5919 | } |
@@ -5897,7 +5992,7 @@ static BC_STATUS xc_program_pushVar(char *code, size_t *bgn, | |||
5897 | 5992 | ||
5898 | #if ENABLE_DC | 5993 | #if ENABLE_DC |
5899 | if (pop || copy) { | 5994 | if (pop || copy) { |
5900 | BcVec *v = xc_program_search(name, true); | 5995 | BcVec *v = xc_program_search(name, BC_TYPE_VAR); |
5901 | BcNum *num = bc_vec_top(v); | 5996 | BcNum *num = bc_vec_top(v); |
5902 | 5997 | ||
5903 | free(name); | 5998 | free(name); |
@@ -6014,16 +6109,19 @@ static BC_STATUS zbc_program_call(char *code, size_t *idx) | |||
6014 | for (i = 0; i < nparams; ++i) { | 6109 | for (i = 0; i < nparams; ++i) { |
6015 | BcResult *arg; | 6110 | BcResult *arg; |
6016 | BcStatus s; | 6111 | BcStatus s; |
6112 | bool arr; | ||
6017 | 6113 | ||
6018 | a = bc_vec_item(&func->autos, nparams - 1 - i); | 6114 | a = bc_vec_item(&func->autos, nparams - 1 - i); |
6019 | arg = bc_vec_top(&G.prog.results); | 6115 | arg = bc_vec_top(&G.prog.results); |
6020 | 6116 | ||
6021 | if ((!a->idx) != (arg->t == XC_RESULT_ARRAY) // array/variable mismatch | 6117 | arr = (a->idx == BC_TYPE_ARRAY || a->idx == BC_TYPE_REF); |
6118 | |||
6119 | if (arr != (arg->t == XC_RESULT_ARRAY) // array/variable mismatch | ||
6022 | // || arg->t == XC_RESULT_STR - impossible, f("str") is not a legal syntax (strings are not bc expressions) | 6120 | // || arg->t == XC_RESULT_STR - impossible, f("str") is not a legal syntax (strings are not bc expressions) |
6023 | ) { | 6121 | ) { |
6024 | RETURN_STATUS(bc_error_variable_is_wrong_type()); | 6122 | RETURN_STATUS(bc_error_variable_is_wrong_type()); |
6025 | } | 6123 | } |
6026 | s = zxc_program_popResultAndCopyToVar(a->name, a->idx); | 6124 | s = zxc_program_popResultAndCopyToVar(a->name, (BcType) a->idx); |
6027 | if (s) RETURN_STATUS(s); | 6125 | if (s) RETURN_STATUS(s); |
6028 | } | 6126 | } |
6029 | 6127 | ||
@@ -6031,12 +6129,13 @@ static BC_STATUS zbc_program_call(char *code, size_t *idx) | |||
6031 | for (; i < func->autos.len; i++, a++) { | 6129 | for (; i < func->autos.len; i++, a++) { |
6032 | BcVec *v; | 6130 | BcVec *v; |
6033 | 6131 | ||
6034 | v = xc_program_search(a->name, a->idx); | 6132 | v = xc_program_search(a->name, (BcType) a->idx); |
6035 | if (a->idx) { | 6133 | if (a->idx == BC_TYPE_VAR) { |
6036 | BcNum n2; | 6134 | BcNum n2; |
6037 | bc_num_init_DEF_SIZE(&n2); | 6135 | bc_num_init_DEF_SIZE(&n2); |
6038 | bc_vec_push(v, &n2); | 6136 | bc_vec_push(v, &n2); |
6039 | } else { | 6137 | } else { |
6138 | //assert(a->idx == BC_TYPE_ARRAY); | ||
6040 | BcVec v2; | 6139 | BcVec v2; |
6041 | bc_array_init(&v2, true); | 6140 | bc_array_init(&v2, true); |
6042 | bc_vec_push(v, &v2); | 6141 | bc_vec_push(v, &v2); |
@@ -6087,7 +6186,7 @@ static BC_STATUS zbc_program_return(char inst) | |||
6087 | a = (void*)f->autos.v; | 6186 | a = (void*)f->autos.v; |
6088 | for (i = 0; i < f->autos.len; i++, a++) { | 6187 | for (i = 0; i < f->autos.len; i++, a++) { |
6089 | BcVec *v; | 6188 | BcVec *v; |
6090 | v = xc_program_search(a->name, a->idx); | 6189 | v = xc_program_search(a->name, (BcType) a->idx); |
6091 | bc_vec_pop(v); | 6190 | bc_vec_pop(v); |
6092 | } | 6191 | } |
6093 | 6192 | ||
@@ -6399,7 +6498,7 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond) | |||
6399 | 6498 | ||
6400 | if (exec) { | 6499 | if (exec) { |
6401 | BcVec *v; | 6500 | BcVec *v; |
6402 | v = xc_program_search(name, true); | 6501 | v = xc_program_search(name, BC_TYPE_VAR); |
6403 | n = bc_vec_top(v); | 6502 | n = bc_vec_top(v); |
6404 | } | 6503 | } |
6405 | 6504 | ||
@@ -6724,7 +6823,7 @@ static BC_STATUS zxc_program_exec(void) | |||
6724 | } | 6823 | } |
6725 | case DC_INST_PUSH_TO_VAR: { | 6824 | case DC_INST_PUSH_TO_VAR: { |
6726 | char *name = xc_program_name(code, &ip->inst_idx); | 6825 | char *name = xc_program_name(code, &ip->inst_idx); |
6727 | s = zxc_program_popResultAndCopyToVar(name, true); | 6826 | s = zxc_program_popResultAndCopyToVar(name, BC_TYPE_VAR); |
6728 | free(name); | 6827 | free(name); |
6729 | break; | 6828 | break; |
6730 | } | 6829 | } |
diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index 610fed5d6..7a2e8534a 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c | |||
@@ -36,17 +36,26 @@ | |||
36 | //config: help | 36 | //config: help |
37 | //config: Detect I2C chips. | 37 | //config: Detect I2C chips. |
38 | //config: | 38 | //config: |
39 | //config:config I2CTRANSFER | ||
40 | //config: bool "i2ctransfer (4.0 kb)" | ||
41 | //config: default y | ||
42 | //config: select PLATFORM_LINUX | ||
43 | //config: help | ||
44 | //config: Send user-defined I2C messages in one transfer. | ||
45 | //config: | ||
39 | 46 | ||
40 | //applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 47 | //applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
41 | //applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 48 | //applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
42 | //applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 49 | //applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
43 | //applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 50 | //applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
51 | //applet:IF_I2CTRANSFER(APPLET(i2ctransfer, BB_DIR_USR_SBIN, BB_SUID_DROP)) | ||
44 | /* not NOEXEC: if hw operation stalls, use less memory in "hung" process */ | 52 | /* not NOEXEC: if hw operation stalls, use less memory in "hung" process */ |
45 | 53 | ||
46 | //kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o | 54 | //kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o |
47 | //kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o | 55 | //kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o |
48 | //kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o | 56 | //kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o |
49 | //kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o | 57 | //kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o |
58 | //kbuild:lib-$(CONFIG_I2CTRANSFER) += i2c_tools.o | ||
50 | 59 | ||
51 | /* | 60 | /* |
52 | * Unsupported stuff: | 61 | * Unsupported stuff: |
@@ -80,12 +89,19 @@ | |||
80 | #define I2C_FUNCS 0x0705 | 89 | #define I2C_FUNCS 0x0705 |
81 | #define I2C_PEC 0x0708 | 90 | #define I2C_PEC 0x0708 |
82 | #define I2C_SMBUS 0x0720 | 91 | #define I2C_SMBUS 0x0720 |
92 | #define I2C_RDWR 0x0707 | ||
93 | #define I2C_RDWR_IOCTL_MAX_MSGS 42 | ||
94 | #define I2C_RDWR_IOCTL_MAX_MSGS_STR "42" | ||
83 | struct i2c_smbus_ioctl_data { | 95 | struct i2c_smbus_ioctl_data { |
84 | __u8 read_write; | 96 | __u8 read_write; |
85 | __u8 command; | 97 | __u8 command; |
86 | __u32 size; | 98 | __u32 size; |
87 | union i2c_smbus_data *data; | 99 | union i2c_smbus_data *data; |
88 | }; | 100 | }; |
101 | struct i2c_rdwr_ioctl_data { | ||
102 | struct i2c_msg *msgs; /* pointers to i2c_msgs */ | ||
103 | __u32 nmsgs; /* number of i2c_msgs */ | ||
104 | }; | ||
89 | /* end linux/i2c-dev.h */ | 105 | /* end linux/i2c-dev.h */ |
90 | 106 | ||
91 | /* | 107 | /* |
@@ -262,7 +278,7 @@ static int i2c_bus_lookup(const char *bus_str) | |||
262 | return xstrtou_range(bus_str, 10, 0, 0xfffff); | 278 | return xstrtou_range(bus_str, 10, 0, 0xfffff); |
263 | } | 279 | } |
264 | 280 | ||
265 | #if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP | 281 | #if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP || ENABLE_I2CTRANSFER |
266 | static int i2c_parse_bus_addr(const char *addr_str) | 282 | static int i2c_parse_bus_addr(const char *addr_str) |
267 | { | 283 | { |
268 | /* Slave address must be in range 0x03 - 0x77. */ | 284 | /* Slave address must be in range 0x03 - 0x77. */ |
@@ -1373,3 +1389,161 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv) | |||
1373 | return 0; | 1389 | return 0; |
1374 | } | 1390 | } |
1375 | #endif /* ENABLE_I2CDETECT */ | 1391 | #endif /* ENABLE_I2CDETECT */ |
1392 | |||
1393 | #if ENABLE_I2CTRANSFER | ||
1394 | static void check_i2c_func(int fd) | ||
1395 | { | ||
1396 | unsigned long funcs; | ||
1397 | |||
1398 | get_funcs_matrix(fd, &funcs); | ||
1399 | |||
1400 | if (!(funcs & I2C_FUNC_I2C)) | ||
1401 | bb_error_msg_and_die("adapter does not support I2C transfers"); | ||
1402 | } | ||
1403 | |||
1404 | //usage:#define i2ctransfer_trivial_usage | ||
1405 | //usage: "[-fay] I2CBUS {rLENGTH[@ADDR] | wLENGTH[@ADDR] DATA...}..." | ||
1406 | //usage:#define i2ctransfer_full_usage "\n\n" | ||
1407 | //usage: "Read/write I2C data in one transfer" | ||
1408 | //usage: "\n" | ||
1409 | //usage: "\n -f Force access to busy addresses" | ||
1410 | //usage: "\n -a Force access to non-regular addresses" | ||
1411 | //usage: "\n -y Disable interactive mode" | ||
1412 | int i2ctransfer_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
1413 | int i2ctransfer_main(int argc UNUSED_PARAM, char **argv) | ||
1414 | { | ||
1415 | enum { | ||
1416 | opt_f = (1 << 0), | ||
1417 | opt_y = (1 << 1), | ||
1418 | opt_a = (1 << 2), | ||
1419 | }; | ||
1420 | int bus_num, bus_addr; | ||
1421 | int fd; | ||
1422 | unsigned opts, first, last; | ||
1423 | int nmsgs, nmsgs_sent, i; | ||
1424 | struct i2c_msg msgs[I2C_RDWR_IOCTL_MAX_MSGS]; | ||
1425 | struct i2c_rdwr_ioctl_data rdwr; | ||
1426 | |||
1427 | memset(msgs, 0, sizeof(msgs)); | ||
1428 | |||
1429 | opts = getopt32(argv, "^" | ||
1430 | "fya" | ||
1431 | "\0" "-2" /* minimum 2 args */ | ||
1432 | ); | ||
1433 | first = 0x03; | ||
1434 | last = 0x77; | ||
1435 | if (opts & opt_a) { | ||
1436 | first = 0x00; | ||
1437 | last = 0x7f; | ||
1438 | } | ||
1439 | |||
1440 | argv += optind; | ||
1441 | bus_num = i2c_bus_lookup(argv[0]); | ||
1442 | fd = i2c_dev_open(bus_num); | ||
1443 | check_i2c_func(fd); | ||
1444 | |||
1445 | bus_addr = -1; | ||
1446 | nmsgs = 0; | ||
1447 | while (*++argv) { | ||
1448 | char *arg_ptr; | ||
1449 | unsigned len; | ||
1450 | uint16_t flags; | ||
1451 | char *end; | ||
1452 | |||
1453 | if (nmsgs >= I2C_RDWR_IOCTL_MAX_MSGS) | ||
1454 | bb_error_msg_and_die("too many messages, max: "I2C_RDWR_IOCTL_MAX_MSGS_STR); | ||
1455 | |||
1456 | flags = 0; | ||
1457 | arg_ptr = *argv; | ||
1458 | switch (*arg_ptr++) { | ||
1459 | case 'r': flags |= I2C_M_RD; break; | ||
1460 | case 'w': break; | ||
1461 | default: | ||
1462 | bb_show_usage(); | ||
1463 | } | ||
1464 | |||
1465 | end = strchr(arg_ptr, '@'); | ||
1466 | if (end) *end = '\0'; | ||
1467 | len = xstrtou_range(arg_ptr, 0, 0, 0xffff); | ||
1468 | if (end) { | ||
1469 | bus_addr = xstrtou_range(end + 1, 0, first, last); | ||
1470 | i2c_set_slave_addr(fd, bus_addr, (opts & opt_f)); | ||
1471 | } else { | ||
1472 | /* Reuse last address if possible */ | ||
1473 | if (bus_addr < 0) | ||
1474 | bb_error_msg_and_die("no address given in '%s'", *argv); | ||
1475 | } | ||
1476 | |||
1477 | msgs[nmsgs].addr = bus_addr; | ||
1478 | msgs[nmsgs].flags = flags; | ||
1479 | msgs[nmsgs].len = len; | ||
1480 | if (len) | ||
1481 | msgs[nmsgs].buf = xzalloc(len); | ||
1482 | |||
1483 | if (!(flags & I2C_M_RD)) { | ||
1484 | /* Consume DATA arg(s) */ | ||
1485 | unsigned buf_idx = 0; | ||
1486 | |||
1487 | while (buf_idx < len) { | ||
1488 | uint8_t data8; | ||
1489 | unsigned long data; | ||
1490 | |||
1491 | arg_ptr = *++argv; | ||
1492 | if (!arg_ptr) | ||
1493 | bb_show_usage(); | ||
1494 | data = strtoul(arg_ptr, &end, 0); | ||
1495 | if (data > 0xff || arg_ptr == end) | ||
1496 | bb_error_msg_and_die("invalid data byte '%s'", *argv); | ||
1497 | |||
1498 | data8 = data; | ||
1499 | while (buf_idx < len) { | ||
1500 | msgs[nmsgs].buf[buf_idx++] = data8; | ||
1501 | if (!*end) | ||
1502 | break; | ||
1503 | switch (*end) { | ||
1504 | /* Pseudo randomness (8 bit AXR with a=13 and b=27) */ | ||
1505 | case 'p': | ||
1506 | data8 = (data8 ^ 27) + 13; | ||
1507 | data8 = (data8 << 1) | (data8 >> 7); | ||
1508 | break; | ||
1509 | case '+': data8++; break; | ||
1510 | case '-': data8--; break; | ||
1511 | case '=': break; | ||
1512 | default: | ||
1513 | bb_error_msg_and_die("invalid data byte suffix: '%s'", | ||
1514 | *argv); | ||
1515 | } | ||
1516 | } | ||
1517 | } | ||
1518 | } | ||
1519 | nmsgs++; | ||
1520 | } | ||
1521 | |||
1522 | if (!(opts & opt_y)) | ||
1523 | confirm_action(bus_addr, 0, 0, 0); | ||
1524 | |||
1525 | rdwr.msgs = msgs; | ||
1526 | rdwr.nmsgs = nmsgs; | ||
1527 | nmsgs_sent = ioctl_or_perror_and_die(fd, I2C_RDWR, &rdwr, "I2C_RDWR"); | ||
1528 | if (nmsgs_sent < nmsgs) | ||
1529 | bb_error_msg("warning: only %u/%u messages sent", nmsgs_sent, nmsgs); | ||
1530 | |||
1531 | for (i = 0; i < nmsgs_sent; i++) { | ||
1532 | if (msgs[i].len != 0 && (msgs[i].flags & I2C_M_RD)) { | ||
1533 | int j; | ||
1534 | for (j = 0; j < msgs[i].len - 1; j++) | ||
1535 | printf("0x%02x ", msgs[i].buf[j]); | ||
1536 | /* Print final byte with newline */ | ||
1537 | printf("0x%02x\n", msgs[i].buf[j]); | ||
1538 | } | ||
1539 | } | ||
1540 | |||
1541 | # if ENABLE_FEATURE_CLEAN_UP | ||
1542 | close(fd); | ||
1543 | for (i = 0; i < nmsgs; i++) | ||
1544 | free(msgs[i].buf); | ||
1545 | # endif | ||
1546 | |||
1547 | return 0; | ||
1548 | } | ||
1549 | #endif /* ENABLE_I2CTRANSFER */ | ||