//NOTE: Many tests have been performed (no longer included in this code) // Including: // dir = (int8_t)dir; // printf(...PRIi8..., (int8_t)dir, ...); // dir = (dir & 0x000000ff); // various castings in the assignment of signedPower, including: // int32_t signedPower = (int32_t)dir * (int32_t)power; // int16_t signedPower = (int16_t)dir * (int32_t)power; // None of these clear up the bug(s). void testBrokenMathAndPrintout(void) { uint8_t power = 127; int8_t dir = -1; int16_t signedPower = (int16_t)power * (int16_t)dir; PRINT_IT(1, power, dir, signedPower); #if INCLUDE_RAND //This case will SELDOMLY be *executed* // but without some potential reassignment to the variable 'dir' // (somewhere) // the bug does not appear if(rand() == 0) { printf("!!! rand() == 0, else{} executed!\n\r"); //THIS VALUE IS NOT EXPECTED TO BE USED // SEE NOTES FOR 'INCLUDE_RAND' dir = ((int8_t)(0)); } #endif //INCLUDE_RAND PRINT_IT(2, power, dir, signedPower); signedPower = (int16_t)power * (int16_t)dir; PRINT_IT(3, power, dir, signedPower); }
/* Prints a usage message based on contents of optlist. * Parameters: * scanner - The scanner, already initialized with scanopt_init(). * fp - The file stream to write to. * usage - Text to be prepended to option list. * Return: Always returns 0 (zero). * The output looks something like this: [indent][option, alias1, alias2...][indent][description line1 description line2...] */ int scanopt_usage (scanopt_t *scanner, FILE *fp, const char *usage) { struct _scanopt_t *s; int i, columns; const int indent = 2; usg_elem *byr_val = NULL; /* option indices sorted by r_val */ usg_elem *store; /* array of preallocated elements. */ int store_idx = 0; usg_elem *ue; int opt_col_width = 0, desc_col_width = 0; int desccol; int print_run = 0; s = (struct _scanopt_t *) scanner; if (usage) { fprintf (fp, "%s\n", usage); } else { fprintf (fp, _("Usage: %s [OPTIONS]...\n"), s->argv[0]); } fprintf (fp, "\n"); /* Sort by r_val and string. Yes, this is O(n*n), but n is small. */ store = malloc((size_t) s->optc * sizeof (usg_elem)); for (i = 0; i < s->optc; i++) { /* grab the next preallocate node. */ ue = store + store_idx++; ue->idx = i; ue->next = ue->alias = NULL; /* insert into list. */ if (!byr_val) byr_val = ue; else { int found_alias = 0; usg_elem **ue_curr, **ptr_if_no_alias = NULL; ue_curr = &byr_val; while (*ue_curr) { if (RVAL (s, (*ue_curr)->idx) == RVAL (s, ue->idx)) { /* push onto the alias list. */ ue_curr = &((*ue_curr)->alias); found_alias = 1; break; } if (!ptr_if_no_alias && strcasecmp (NAME (s, (*ue_curr)->idx), NAME (s, ue->idx)) > 0) { ptr_if_no_alias = ue_curr; } ue_curr = &((*ue_curr)->next); } if (!found_alias && ptr_if_no_alias) ue_curr = ptr_if_no_alias; ue->next = *ue_curr; *ue_curr = ue; } } #if 0 if (1) { printf ("ORIGINAL:\n"); for (i = 0; i < s->optc; i++) printf ("%2d: %s\n", i, NAME (s, i)); printf ("SORTED:\n"); ue = byr_val; while (ue) { usg_elem *ue2; printf ("%2d: %s\n", ue->idx, NAME (s, ue->idx)); for (ue2 = ue->alias; ue2; ue2 = ue2->next) printf (" +---> %2d: %s\n", ue2->idx, NAME (s, ue2->idx)); ue = ue->next; } } #endif /* Now build each row of output. */ /* first pass calculate how much room we need. */ for (ue = byr_val; ue; ue = ue->next) { usg_elem *ap; int len; len = PRINTLEN(s, ue->idx); for (ap = ue->alias; ap; ap = ap->next) { len += PRINTLEN(s, ap->idx) + (int) strlen(", "); } if (len > opt_col_width) opt_col_width = len; /* It's much easier to calculate length for description column! */ len = (int) strlen (DESC (s, ue->idx)); if (len > desc_col_width) desc_col_width = len; } /* Determine how much room we have, and how much we will allocate to each col. * Do not address pathological cases. Output will just be ugly. */ columns = get_cols () - 1; if (opt_col_width + desc_col_width + indent * 2 > columns) { /* opt col gets whatever it wants. we'll wrap the desc col. */ desc_col_width = columns - (opt_col_width + indent * 2); if (desc_col_width < 14) /* 14 is arbitrary lower limit on desc width. */ desc_col_width = INT_MAX; } desccol = opt_col_width + indent * 2; #define PRINT_SPACES(fp,n) \ fprintf((fp), "%*s", (n), "") /* Second pass (same as above loop), this time we print. */ /* Sloppy hack: We iterate twice. The first time we print short and long options. The second time we print those lines that have ONLY long options. */ while (print_run++ < 2) { for (ue = byr_val; ue; ue = ue->next) { usg_elem *ap; int nwords = 0, nchars = 0, has_short = 0; /* TODO: get has_short schtick to work */ has_short = !(FLAGS (s, ue->idx) & IS_LONG); for (ap = ue->alias; ap; ap = ap->next) { if (!(FLAGS (s, ap->idx) & IS_LONG)) { has_short = 1; break; } } if ((print_run == 1 && !has_short) || (print_run == 2 && has_short)) continue; PRINT_SPACES (fp, indent); nchars += indent; /* Print, adding a ", " between aliases. */ #define PRINT_IT(i) do{\ if(nwords++)\ nchars+=fprintf(fp,", ");\ nchars+=fprintf(fp,"%s",s->options[i].opt_fmt);\ }while(0) if (!(FLAGS (s, ue->idx) & IS_LONG)) PRINT_IT (ue->idx); /* print short aliases first. */ for (ap = ue->alias; ap; ap = ap->next) { if (!(FLAGS (s, ap->idx) & IS_LONG)) PRINT_IT (ap->idx); } if (FLAGS (s, ue->idx) & IS_LONG) PRINT_IT (ue->idx); /* repeat the above loop, this time for long aliases. */ for (ap = ue->alias; ap; ap = ap->next) { if (FLAGS (s, ap->idx) & IS_LONG) PRINT_IT (ap->idx); } /* pad to desccol */ PRINT_SPACES (fp, desccol - nchars); /* Print description, wrapped to desc_col_width columns. */ if (1) { const char *pstart; pstart = DESC (s, ue->idx); while (1) { int n = 0; const char *lastws = NULL, *p; p = pstart; while (*p && n < desc_col_width && *p != '\n') { if (isspace ((unsigned char)(*p)) || *p == '-') lastws = p; n++; p++; } if (!*p) { /* hit end of desc. done. */ fprintf (fp, "%s\n", pstart); break; } else if (*p == '\n') { /* print everything up to here then wrap. */ fprintf (fp, "%.*s\n", n, pstart); PRINT_SPACES (fp, desccol); pstart = p + 1; continue; } else { /* we hit the edge of the screen. wrap at space if possible. */ if (lastws) { fprintf (fp, "%.*s\n", (int)(lastws - pstart), pstart); pstart = lastws + 1; } else { fprintf (fp, "%.*s\n", n, pstart); pstart = p + 1; } PRINT_SPACES (fp, desccol); continue; } } } } } /* end while */ free (store); return 0; }