pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00039 #ifdef HAVE_CONFIG_H 00040 #include "config.h" 00041 #endif 00042 00043 #include "global.h" 00044 00045 #include "pcb-printf.h" 00046 00047 /* Helper macros for tables */ 00048 #define MM_TO_COORD3(a,b,c) MM_TO_COORD (a), MM_TO_COORD (b), MM_TO_COORD (c) 00049 #define MIL_TO_COORD3(a,b,c) MIL_TO_COORD (a), MIL_TO_COORD (b), MIL_TO_COORD (c) 00050 #define MM_TO_COORD5(a,b,c,d,e) MM_TO_COORD (a), MM_TO_COORD (b), MM_TO_COORD (c), \ 00051 MM_TO_COORD (d), MM_TO_COORD (e) 00052 #define MIL_TO_COORD5(a,b,c,d,e) MIL_TO_COORD (a), MIL_TO_COORD (b), MIL_TO_COORD (c), \ 00053 MIL_TO_COORD (d), MIL_TO_COORD (e) 00054 00062 static Unit Units[] = { 00063 { 0, "km", NULL, 'k', 0.000001, METRIC, ALLOW_KM, 5, 00064 0.00005, 0.0005, 0.0025, 0.05, 0.25, 00065 { "" } }, 00066 { 0, "m", NULL, 'f', 0.001, METRIC, ALLOW_M, 5, 00067 0.0005, 0.005, 0.025, 0.5, 2.5, 00068 { "" } }, 00069 { 0, "cm", NULL, 'e', 0.1, METRIC, ALLOW_CM, 5, 00070 0.005, 0.05, 0.25, 5, 25, 00071 { "" } }, 00072 { 0, "mm", NULL, 'm', 1, METRIC, ALLOW_MM, 4, 00073 0.005, 0.05, 0.25, 5, 25, 00074 { "" } }, 00075 { 0, "um", NULL, 'u', 1000, METRIC, ALLOW_UM, 2, 00076 0.005, 0.05, 0.25, 5, 25, 00077 { "" } }, 00078 { 0, "nm", NULL, 'n', 1000000, METRIC, ALLOW_NM, 0, 00079 5, 50, 2500, 5000, 25000, 00080 { "" } }, 00081 /* Hack: Pixels get parsed like nanometers. If the value of the 00082 * resulting integer is sufficiently small, the code interprets 00083 * it a screen pixels. This affects rat thickness. */ 00084 { 0, "px", NULL, 'n', 1000000, METRIC, ALLOW_NM, 0, 00085 5, 50, 2500, 5000, 25000, 00086 { "" } }, 00087 00088 00089 { 0, "in", NULL, 'i', 0.001, IMPERIAL, ALLOW_IN, 5, 00090 0.1, 1.0, 5.0, 25, 100, 00091 { "inch" } }, 00092 { 0, "mil", NULL, 'l', 1, IMPERIAL, ALLOW_MIL, 2, 00093 0.1, 1.0, 10, 100, 1000, 00094 { "" } }, 00095 { 0, "dmil", NULL, 't', 10, IMPERIAL, ALLOW_DMIL, 0, 00096 1, 10, 100, 1000, 10000, 00097 { "" } }, 00098 { 0, "cmil", NULL, 'c', 100, IMPERIAL, ALLOW_CMIL, 0, 00099 1, 10, 100, 1000, 10000, 00100 { "pcb" } } 00101 }; 00102 #define N_UNITS ((int) (sizeof Units / sizeof Units[0])) 00103 00111 void initialize_units() 00112 { 00113 int i; 00114 for (i = 0; i < N_UNITS; ++i) 00115 { 00116 Units[i].index = i; 00117 Units[i].in_suffix = _(Units[i].suffix); 00118 } 00119 } 00120 00134 enum e_allow set_allow_readable(enum e_allow new_mask) 00135 { 00136 static enum e_allow readable_mask = ALLOW_READABLE; 00137 if (new_mask != 0) 00138 readable_mask = new_mask; 00139 return readable_mask; 00140 } 00141 00142 00143 /* TABLE FORMAT | default | min | max 00144 * grid | | | 00145 * size | | | 00146 * line | | | 00147 * clear | | | 00148 */ 00149 static Increments increments_metric = { 00150 "mm", 00151 MM_TO_COORD3 (0.1, 0.01, 1.0), 00152 MM_TO_COORD3 (0.2, 0.01, 0.5), 00153 MM_TO_COORD3 (0.1, 0.005, 0.5), 00154 MM_TO_COORD3 (0.05, 0.005, 0.5) 00155 }; 00156 static Increments increments_imperial = { 00157 "mil", 00158 MIL_TO_COORD3 (5, 1, 25), 00159 MIL_TO_COORD3 (10, 1, 10), 00160 MIL_TO_COORD3 (5, 0.5, 10), 00161 MIL_TO_COORD3 (2, 0.5, 10) 00162 }; 00163 00175 const Unit *get_unit_struct (const char *const_suffix) 00176 { 00177 int i; 00178 int s_len = 0; 00179 /* Turn given suffix into something we can modify... */ 00180 char *m_suffix = g_strdup (const_suffix); 00181 /* ...and store this in a pointer we can move. */ 00182 char *suffix = m_suffix; 00183 00184 /* Determine bounds */ 00185 while (isspace (*suffix)) 00186 ++suffix; 00187 while (isalnum (suffix[s_len])) 00188 ++s_len; 00189 00190 /* Also understand plural suffixes: "inches", "mils" */ 00191 if (s_len > 2) 00192 { 00193 if (suffix[s_len - 2] == 'e' && suffix[s_len - 1] == 's') 00194 suffix[s_len - 2] = 0; 00195 else if (suffix[s_len - 1] == 's') 00196 suffix[s_len - 1] = 0; 00197 } 00198 00199 /* Do lookup */ 00200 if (*suffix && s_len > 0) 00201 for (i = 0; i < N_UNITS; ++i) 00202 if (strncmp (suffix, Units[i].suffix, s_len) == 0 || 00203 strncmp (suffix, Units[i].alias[0], s_len) == 0) 00204 { 00205 g_free (m_suffix); 00206 return &Units[i]; 00207 } 00208 g_free (m_suffix); 00209 return NULL; 00210 } 00211 00212 void copy_nonzero_increments (Increments *dst, const Increments *src) 00213 { 00214 if (src->grid >= dst->grid_min && src->grid <= dst->grid_max) 00215 dst->grid = src->grid; 00216 if (src->line >= dst->line_min && src->line <= dst->line_max) 00217 dst->line = src->line; 00218 if (src->size >= dst->size_min && src->size <= dst->size_max) 00219 dst->size = src->size; 00220 if (src->clear >= dst->clear_min && src->clear <= dst->clear_max) 00221 dst->clear = src->clear; 00222 } 00223 00224 /* ACCESSORS */ 00225 00231 const Unit *get_unit_list (void) 00232 { 00233 return Units; 00234 } 00235 00239 int get_n_units (void) 00240 { 00241 return N_UNITS; 00242 } 00243 00251 Increments *get_increments_struct (enum e_family family) 00252 { 00253 switch (family) 00254 { 00255 case METRIC: 00256 return &increments_metric; 00257 case IMPERIAL: 00258 return &increments_imperial; 00259 } 00260 return NULL; 00261 } 00262 00271 double coord_to_unit (const Unit *unit, Coord x) 00272 { 00273 double base; 00274 if (unit == NULL) 00275 return -1; 00276 base = unit->family == METRIC 00277 ? COORD_TO_MM (x) 00278 : COORD_TO_MIL (x); 00279 return unit->scale_factor * base; 00280 } 00281 00290 Coord unit_to_coord (const Unit *unit, double x) 00291 { 00292 double base; 00293 if (unit == NULL) 00294 return -1; 00295 base = unit->family == METRIC 00296 ? MM_TO_COORD (x) 00297 : MIL_TO_COORD (x); 00298 return DOUBLE_TO_COORD (base / unit->scale_factor); 00299 } 00300 00301 static int min_sig_figs(double d) 00302 { 00303 char buf[50]; 00304 int rv; 00305 00306 if(d == 0) return 0; 00307 00308 /* Normalize to x.xxxx... form */ 00309 if(d < 0) d *= -1; 00310 while(d >= 10) d /= 10; 00311 while(d < 1) d *= 10; 00312 00313 rv = sprintf(buf, "%g", d); 00314 return rv; 00315 } 00316 00334 static gchar *CoordsToString(Coord coord[], int n_coords, const char *printf_spec, enum e_allow allow, enum e_suffix suffix_type) 00335 { 00336 GString *buff; 00337 gchar *printf_buff; 00338 gchar filemode_buff[G_ASCII_DTOSTR_BUF_SIZE]; 00339 enum e_family family; 00340 double *value; 00341 const char *suffix; 00342 int i, n; 00343 00344 value = malloc (n_coords * sizeof *value); 00345 buff = g_string_new (""); 00346 00347 /* Sanity checks */ 00348 if (buff == NULL || value == NULL) 00349 return NULL; 00350 if (allow == 0) 00351 allow = ALLOW_ALL; 00352 if (printf_spec == NULL) 00353 printf_spec = ""; 00354 00355 /* Check our freedom in choosing units */ 00356 if ((allow & ALLOW_IMPERIAL) == 0) 00357 family = METRIC; 00358 else if ((allow & ALLOW_METRIC) == 0) 00359 family = IMPERIAL; 00360 else 00361 { 00362 int met_votes = 0, 00363 imp_votes = 0; 00364 00365 for (i = 0; i < n_coords; ++i) 00366 if(min_sig_figs(COORD_TO_MIL(coord[i])) < min_sig_figs(COORD_TO_MM(coord[i]))) 00367 ++imp_votes; 00368 else 00369 ++met_votes; 00370 00371 if (imp_votes > met_votes) 00372 family = IMPERIAL; 00373 else 00374 family = METRIC; 00375 } 00376 00377 /* Set base unit */ 00378 for (i = 0; i < n_coords; ++i) 00379 { 00380 switch (family) 00381 { 00382 case METRIC: value[i] = COORD_TO_MM (coord[i]); break; 00383 case IMPERIAL: value[i] = COORD_TO_MIL (coord[i]); break; 00384 } 00385 } 00386 00387 /* Determine scale factor -- find smallest unit that brings 00388 * the whole group above unity */ 00389 for (n = 0; n < N_UNITS; ++n) 00390 { 00391 if ((Units[n].allow & allow) != 0 && (Units[n].family == family)) 00392 { 00393 int n_above_one = 0; 00394 00395 for (i = 0; i < n_coords; ++i) 00396 if (fabs(value[i] * Units[n].scale_factor) > 1) 00397 ++n_above_one; 00398 if (n_above_one == n_coords) 00399 break; 00400 } 00401 } 00402 /* If nothing worked, wind back to the smallest allowable unit */ 00403 if (n == N_UNITS) 00404 { 00405 do { 00406 --n; 00407 } while ((Units[n].allow & allow) == 0 || Units[n].family != family); 00408 } 00409 00410 /* Apply scale factor */ 00411 suffix = Units[n].suffix; 00412 for (i = 0; i < n_coords; ++i) 00413 value[i] = value[i] * Units[n].scale_factor; 00414 00415 /* Create sprintf specifier, using default_prec no precision is given */ 00416 i = 0; 00417 while (printf_spec[i] == '%' || isdigit(printf_spec[i]) || 00418 printf_spec[i] == '-' || printf_spec[i] == '+' || 00419 printf_spec[i] == '#') 00420 ++i; 00421 if (printf_spec[i] == '.') 00422 printf_buff = g_strdup_printf (", %sf", printf_spec); 00423 else 00424 printf_buff = g_strdup_printf (", %s.%df", printf_spec, Units[n].default_prec); 00425 00426 /* Actually sprintf the values in place 00427 * (+ 2 skips the ", " for first value) */ 00428 if (n_coords > 1) 00429 g_string_append_c (buff, '('); 00430 if (suffix_type == FILE_MODE || suffix_type == FILE_MODE_NO_SUFFIX) 00431 { 00432 g_ascii_formatd (filemode_buff, sizeof filemode_buff, printf_buff + 2, value[0]); 00433 g_string_append_printf (buff, "%s", filemode_buff); 00434 } 00435 else 00436 g_string_append_printf (buff, printf_buff + 2, value[0]); 00437 for (i = 1; i < n_coords; ++i) 00438 { 00439 if (suffix_type == FILE_MODE || suffix_type == FILE_MODE_NO_SUFFIX) 00440 { 00441 g_ascii_formatd (filemode_buff, sizeof filemode_buff, printf_buff, value[i]); 00442 g_string_append_printf (buff, "%s", filemode_buff); 00443 } 00444 else 00445 g_string_append_printf (buff, printf_buff, value[i]); 00446 } 00447 if (n_coords > 1) 00448 g_string_append_c (buff, ')'); 00449 /* Append suffix */ 00450 if (value[0] != 0 || n_coords > 1) 00451 { 00452 switch (suffix_type) 00453 { 00454 case NO_SUFFIX: 00455 case FILE_MODE_NO_SUFFIX: 00456 break; 00457 case SUFFIX: 00458 g_string_append_printf (buff, " %s", suffix); 00459 break; 00460 case FILE_MODE: 00461 g_string_append_printf (buff, "%s", suffix); 00462 break; 00463 } 00464 } 00465 00466 g_free (printf_buff); 00467 free (value); 00468 /* Return just the gchar* part of our string */ 00469 return g_string_free (buff, FALSE); 00470 } 00471 00484 gchar *pcb_vprintf(const char *fmt, va_list args) 00485 { 00486 GString *string = g_string_new (""); 00487 GString *spec = g_string_new (""); 00488 00489 enum e_allow mask = ALLOW_ALL; 00490 00491 if (string == NULL || spec == NULL) 00492 return NULL; 00493 00494 while(*fmt) 00495 { 00496 enum e_suffix suffix = NO_SUFFIX; 00497 00498 if(*fmt == '%') 00499 { 00500 gchar *unit_str = NULL; 00501 const char *ext_unit = ""; 00502 Coord value[10]; 00503 int count, i, done; 00504 00505 g_string_assign (spec, "%"); 00506 00507 done = 0; 00508 while ( ! done && fmt++ && *fmt) 00509 { 00510 switch (*fmt) 00511 { 00512 /* Our sub-specifiers */ 00513 case '#': 00514 mask = ALLOW_CMIL; /* This must be pcb's base unit */ 00515 break; 00516 case '$': 00517 suffix = (suffix == NO_SUFFIX) ? SUFFIX : FILE_MODE; 00518 break; 00519 case '`': 00520 suffix = (suffix == SUFFIX) ? FILE_MODE : FILE_MODE_NO_SUFFIX; 00521 break; 00522 /* Printf sub-specifiers */ 00523 case '*': 00524 g_string_append_printf (spec, "%d", va_arg (args, int)); 00525 break; 00526 case '.': 00527 case ' ': 00528 //case '#': (duplicate) 00529 case 'l': 00530 case 'L': 00531 case 'h': 00532 case '+': 00533 case '-': 00534 case '0': 00535 case '1': 00536 case '2': 00537 case '3': 00538 case '4': 00539 case '5': 00540 case '6': 00541 case '7': 00542 case '8': 00543 case '9': 00544 g_string_append_c (spec, *fmt); 00545 break; 00546 default: 00547 done = 1; 00548 } 00549 } 00550 00551 /* Tack full specifier onto specifier */ 00552 if (*fmt != 'm') 00553 g_string_append_c (spec, *fmt); 00554 switch(*fmt) 00555 { 00556 /* Printf specs */ 00557 case 'o': case 'i': case 'd': 00558 case 'u': case 'x': case 'X': 00559 if(strchr (spec->str, 'l')) 00560 { 00561 if(strchr (spec->str, 'l') != strrchr (spec->str, 'l')) 00562 unit_str = g_strdup_printf (spec->str, va_arg(args, long long)); 00563 else 00564 unit_str = g_strdup_printf (spec->str, va_arg(args, long)); 00565 } 00566 else 00567 { 00568 unit_str = g_strdup_printf (spec->str, va_arg(args, int)); 00569 } 00570 break; 00571 case 'e': case 'E': 00572 case 'f': case 'F': 00573 case 'g': case 'G': 00574 if(suffix == FILE_MODE || suffix == FILE_MODE_NO_SUFFIX) 00575 { 00576 gchar buffer[128]; 00577 g_ascii_formatd (buffer, 128, spec->str, va_arg(args, double)); 00578 unit_str = g_strdup_printf ("%s", buffer); 00579 } 00580 else 00581 unit_str = g_strdup_printf (spec->str, va_arg(args, double)); 00582 break; 00583 case 'c': 00584 if(strchr (spec->str, 'l') && sizeof(int) <= sizeof(wchar_t)) 00585 unit_str = g_strdup_printf (spec->str, va_arg(args, wchar_t)); 00586 else 00587 unit_str = g_strdup_printf (spec->str, va_arg(args, int)); 00588 break; 00589 case 's': 00590 if(strchr (spec->str, 'l')) 00591 unit_str = g_strdup_printf (spec->str, va_arg(args, wchar_t *)); 00592 else 00593 unit_str = g_strdup_printf (spec->str, va_arg(args, char *)); 00594 break; 00595 case 'n': 00596 /* Depending on gcc settings, this will probably break with 00597 * some silly "can't put %n in writeable data space" message */ 00598 unit_str = g_strdup_printf (spec->str, va_arg(args, int *)); 00599 break; 00600 case 'p': 00601 unit_str = g_strdup_printf (spec->str, va_arg(args, void *)); 00602 break; 00603 case '%': 00604 g_string_append_c (string, '%'); 00605 break; 00606 /* Our specs */ 00607 case 'm': 00608 ++fmt; 00609 if (*fmt == '*') 00610 ext_unit = va_arg(args, const char *); 00611 if (*fmt != '+' && *fmt != 'a') 00612 value[0] = va_arg(args, Coord); 00613 count = 1; 00614 switch(*fmt) 00615 { 00616 case 's': unit_str = CoordsToString(value, 1, spec->str, ALLOW_MM | ALLOW_MIL, suffix); break; 00617 case 'S': unit_str = CoordsToString(value, 1, spec->str, mask & ALLOW_ALL, suffix); break; 00618 case 'M': unit_str = CoordsToString(value, 1, spec->str, mask & ALLOW_METRIC, suffix); break; 00619 case 'L': unit_str = CoordsToString(value, 1, spec->str, mask & ALLOW_IMPERIAL, suffix); break; 00620 case 'r': unit_str = CoordsToString(value, 1, spec->str, set_allow_readable(0), FILE_MODE); break; 00621 /* All these fallthroughs are deliberate */ 00622 case '9': value[count++] = va_arg(args, Coord); 00623 case '8': value[count++] = va_arg(args, Coord); 00624 case '7': value[count++] = va_arg(args, Coord); 00625 case '6': value[count++] = va_arg(args, Coord); 00626 case '5': value[count++] = va_arg(args, Coord); 00627 case '4': value[count++] = va_arg(args, Coord); 00628 case '3': value[count++] = va_arg(args, Coord); 00629 case '2': 00630 case 'D': 00631 value[count++] = va_arg(args, Coord); 00632 unit_str = CoordsToString(value, count, spec->str, mask & ALLOW_ALL, suffix); 00633 break; 00634 case 'd': 00635 value[1] = va_arg(args, Coord); 00636 unit_str = CoordsToString(value, 2, spec->str, ALLOW_MM | ALLOW_MIL, suffix); 00637 break; 00638 case '*': 00639 for (i = 0; i < N_UNITS; ++i) 00640 if (strcmp (ext_unit, Units[i].suffix) == 0) 00641 unit_str = CoordsToString(value, 1, spec->str, Units[i].allow, suffix); 00642 if (unit_str == NULL) 00643 unit_str = CoordsToString(value, 1, spec->str, mask & ALLOW_ALL, suffix); 00644 break; 00645 case 'a': 00646 g_string_append (spec, "f"); 00647 if (suffix == SUFFIX) 00648 g_string_append (spec, " deg"); 00649 unit_str = g_strdup_printf (spec->str, (double) va_arg(args, Angle)); 00650 break; 00651 case '+': 00652 mask = va_arg(args, enum e_allow); 00653 break; 00654 default: 00655 for (i = 0; i < N_UNITS; ++i) 00656 if (*fmt == Units[i].printf_code) 00657 unit_str = CoordsToString(value, 1, spec->str, Units[i].allow, suffix); 00658 if (unit_str == NULL) 00659 unit_str = CoordsToString(value, 1, spec->str, ALLOW_ALL, suffix); 00660 break; 00661 } 00662 break; 00663 } 00664 if (unit_str != NULL) 00665 { 00666 g_string_append (string, unit_str); 00667 g_free (unit_str); 00668 } 00669 } 00670 else 00671 g_string_append_c (string, *fmt); 00672 ++fmt; 00673 } 00674 g_string_free (spec, TRUE); 00675 /* Return just the gchar* part of our string */ 00676 return g_string_free (string, FALSE); 00677 } 00678 00679 00696 int pcb_snprintf(char *string, size_t size, const char *fmt, ...) 00697 { 00698 gchar *tmp; 00699 gsize length; 00700 00701 va_list args; 00702 va_start(args, fmt); 00703 00704 tmp = pcb_vprintf (fmt, args); 00705 length = strlen (tmp); 00706 strncpy (string, tmp, size); 00707 string[size - 1] = '\0'; 00708 00709 g_free (tmp); 00710 va_end(args); 00711 00712 return length; 00713 } 00714 00723 int pcb_fprintf(FILE *fh, const char *fmt, ...) 00724 { 00725 int rv; 00726 gchar *tmp; 00727 00728 va_list args; 00729 va_start(args, fmt); 00730 00731 if (fh == NULL) 00732 rv = -1; 00733 else 00734 { 00735 tmp = pcb_vprintf (fmt, args); 00736 rv = fprintf (fh, "%s", tmp); 00737 g_free (tmp); 00738 } 00739 00740 va_end(args); 00741 return rv; 00742 } 00743 00751 int pcb_printf(const char *fmt, ...) 00752 { 00753 int rv; 00754 gchar *tmp; 00755 00756 va_list args; 00757 va_start(args, fmt); 00758 00759 tmp = pcb_vprintf (fmt, args); 00760 rv = printf ("%s", tmp); 00761 g_free (tmp); 00762 00763 va_end(args); 00764 return rv; 00765 } 00766 00775 char *pcb_g_strdup_printf(const char *fmt, ...) 00776 { 00777 gchar *tmp; 00778 00779 va_list args; 00780 va_start(args, fmt); 00781 tmp = pcb_vprintf (fmt, args); 00782 va_end(args); 00783 return tmp; 00784 } 00785 00786 #ifdef PCB_UNIT_TEST 00787 void 00788 pcb_printf_register_tests () 00789 { 00790 g_test_add_func ("/pcb-printf/test-unit", pcb_printf_test_unit); 00791 g_test_add_func ("/pcb-printf/test-printf", pcb_printf_test_printf); 00792 } 00793 00794 void 00795 pcb_printf_test_unit () 00796 { 00797 Coord c[] = { 00798 unit_to_coord (get_unit_struct ("m"), 1.0), 00799 unit_to_coord (get_unit_struct ("mm"), 1.0), 00800 unit_to_coord (get_unit_struct ("um"), 1.0), 00801 unit_to_coord (get_unit_struct ("mil"), 1.0), 00802 unit_to_coord (get_unit_struct ("mil"), 0.5), 00803 unit_to_coord (get_unit_struct ("nm"), 67) 00804 }; 00805 00806 /* Loop unrolled for ease of pinpointing failure */ 00807 g_assert (get_unit_struct ("m") != NULL); 00808 00809 g_assert_cmpuint (c[0], ==, 1000000000); 00810 g_assert_cmpuint (c[1], ==, 1000000); 00811 g_assert_cmpuint (c[2], ==, 1000); 00812 g_assert_cmpuint (c[3], ==, 25400); 00813 g_assert_cmpuint (c[4], ==, 12700); 00814 g_assert_cmpuint (c[5], ==, 67); 00815 } 00816 00817 void 00818 pcb_printf_test_printf () 00819 { 00820 Coord c = unit_to_coord (get_unit_struct ("nm"), 314); 00821 Coord d = unit_to_coord (get_unit_struct ("nm"), 218); 00822 Coord e = unit_to_coord (get_unit_struct ("mm"), 101); 00823 Coord f = unit_to_coord (get_unit_struct ("mil"), 3); 00824 00825 g_assert_cmpstr (pcb_g_strdup_printf ("%mn", c), ==, "314"); 00826 g_assert_cmpstr (pcb_g_strdup_printf ("%$mn", c), ==, "314 nm"); 00827 g_assert_cmpstr (pcb_g_strdup_printf ("%mu", c), ==, "0.31"); 00828 g_assert_cmpstr (pcb_g_strdup_printf ("%.3mu", c), ==, "0.314"); 00829 g_assert_cmpstr (pcb_g_strdup_printf ("%$mu", c), ==, "0.31 um"); 00830 g_assert_cmpstr (pcb_g_strdup_printf ("%$ml", c), ==, "0.01 mil"); 00831 g_assert_cmpstr (pcb_g_strdup_printf ("%.5$ml", c), ==, "0.01236 mil"); 00832 00833 g_assert_cmpstr (pcb_g_strdup_printf ("%mn", e), ==, "101000000"); 00834 g_assert_cmpstr (pcb_g_strdup_printf ("%$mn", e), ==, "101000000 nm"); 00835 g_assert_cmpstr (pcb_g_strdup_printf ("%mu", e), ==, "101000.00"); 00836 g_assert_cmpstr (pcb_g_strdup_printf ("%$mu", e), ==, "101000.00 um"); 00837 g_assert_cmpstr (pcb_g_strdup_printf ("%ms", e), ==, "101.0000"); 00838 g_assert_cmpstr (pcb_g_strdup_printf ("%$ms", e), ==, "101.0000 mm"); 00839 g_assert_cmpstr (pcb_g_strdup_printf ("%mS", e), ==, "10.10000"); 00840 g_assert_cmpstr (pcb_g_strdup_printf ("%$mS", e), ==, "10.10000 cm"); 00841 g_assert_cmpstr (pcb_g_strdup_printf ("%$ml", e), ==, "3976.38 mil"); 00842 g_assert_cmpstr (pcb_g_strdup_printf ("%.5$ml", e), ==, "3976.37795 mil"); 00843 00844 g_assert_cmpstr (pcb_g_strdup_printf ("%mn", f), ==, "76200"); 00845 g_assert_cmpstr (pcb_g_strdup_printf ("%$mn", f), ==, "76200 nm"); 00846 g_assert_cmpstr (pcb_g_strdup_printf ("%mm", f), ==, "0.0762"); 00847 g_assert_cmpstr (pcb_g_strdup_printf ("%$mm", f), ==, "0.0762 mm"); 00848 g_assert_cmpstr (pcb_g_strdup_printf ("%ms", f), ==, "3.00"); 00849 g_assert_cmpstr (pcb_g_strdup_printf ("%$ms", f), ==, "3.00 mil"); 00850 g_assert_cmpstr (pcb_g_strdup_printf ("%mS", f), ==, "3.00"); 00851 g_assert_cmpstr (pcb_g_strdup_printf ("%$mS", f), ==, "3.00 mil"); 00852 00853 g_assert_cmpstr (pcb_g_strdup_printf ("%ms", c), ==, "0.0003"); 00854 g_assert_cmpstr (pcb_g_strdup_printf ("%$ms", c), ==, "0.0003 mm"); 00855 g_assert_cmpstr (pcb_g_strdup_printf ("%mS", c), ==, "314"); 00856 g_assert_cmpstr (pcb_g_strdup_printf ("%$mS", c), ==, "314 nm"); 00857 00858 g_assert_cmpstr (pcb_g_strdup_printf ("%mD", c, d), ==, "(314, 218)"); 00859 g_assert_cmpstr (pcb_g_strdup_printf ("%$mD", c, d), ==, "(314, 218) nm"); 00860 00861 g_assert_cmpstr (pcb_g_strdup_printf ("%`f", 7.2456), ==, "7.245600"); 00862 g_assert_cmpstr (pcb_g_strdup_printf ("%`.2f", 7.2456), ==, "7.25"); 00863 00864 /* Some crashes noticed by Peter Clifton */ 00865 /* specifiers in "wrong" order (should work fine) */ 00866 g_assert_cmpstr (pcb_g_strdup_printf ("%$#mS", e), ==, "397638 cmil"); 00867 /* invalid specifier (should passthrough to g_strdup_printf and output nothing) */ 00868 g_assert_cmpstr (pcb_g_strdup_printf ("%#S", e), ==, ""); 00869 } 00870 00871 #endif