--- /n/sources/plan9/sys/src/libmp/port/strtomp.c Sat Jun 14 00:00:00 2025 +++ /sys/src/libmp/port/strtomp.c Tue Jun 23 00:00:00 2026 @@ -1,6 +1,5 @@ #include "os.h" #include -#include #include "dat.h" static struct { @@ -44,21 +43,25 @@ init(void) } static char* -from16(char *a, mpint *b) +frompow2(char *a, mpint *b, int s) { char *p, *next; int i; mpdigit x; + int sn; + sn = 1<= sn) break; - mpbits(b, (p-a)*4); + + mpbits(b, (p-a)*s); b->top = 0; next = p; + while(p > a){ x = 0; - for(i = 0; i < Dbits; i += 4){ + for(i = 0; i < Dbits; i += s){ if(p <= a) break; x |= tab.t16[*(uchar*)--p]<= 8) + break; + + mpbits(b, (p-a)*3); + b->top = 0; + next = p; + + i = 0; + x = y = 0; + while(p > a){ + y = tab.t10[*(uchar*)--p]; + x |= y << i; + i += 3; + if(i >= Dbits){ +Digout: + i -= Dbits; + b->p[b->top++] = x; + x = y >> 3-i; + } + } + if(i > 0) + goto Digout; + + return next; +} + static ulong mppow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; @@ -111,42 +148,25 @@ from10(char *a, mpint *b) } static char* -from64(char *a, mpint *b) -{ - char *buf = a; - uchar *p; - int n, m; - - for(; tab.t64[*(uchar*)a] != INVAL; a++) - ; - n = a-buf; - mpbits(b, n*6); - p = malloc(n); - if(p == nil) - return a; - m = dec64(p, n, buf, n); - betomp(p, m, b); - free(p); - return a; -} - -static char* -from32(char *a, mpint *b) +fromdecx(char *a, mpint *b, uchar tab[256], int (*dec)(uchar*, int, char*, int)) { char *buf = a; uchar *p; int n, m; - for(; tab.t64[*(uchar*)a] != INVAL; a++) + b->top = 0; + for(; tab[*(uchar*)a] != INVAL; a++) ; n = a-buf; - mpbits(b, n*5); - p = malloc(n); - if(p == nil) - return a; - m = dec32(p, n, buf, n); - betomp(p, m, b); - free(p); + if(n > 0){ + p = malloc(n); + if(p == nil) + sysfatal("malloc: %r"); + m = (*dec)(p, n, buf, n); + if(m > 0) + betomp(p, m, b); + free(p); + } return a; } @@ -177,29 +197,56 @@ strtomp(char *a, char **pp, int base, mpint *b) break; } + if(base == 0){ + base = 10; + if(a[0] == '0'){ + if(a[1] == 'x' || a[1] == 'X') { + a += 2; + base = 16; + } else if(a[1] == 'b' || a[1] == 'B') { + a += 2; + base = 2; + } else if(a[1] >= '0' && a[1] <= '7') { + a++; + base = 8; + } + } + } + switch(base){ + case 2: + e = frompow2(a, b, 1); + break; + case 4: + e = frompow2(a, b, 2); + break; + case 8: + e = from8(a, b); + break; case 10: e = from10(a, b); break; - default: case 16: - e = from16(a, b); + e = frompow2(a, b, 4); break; case 32: - e = from32(a, b); + e = fromdecx(a, b, tab.t32, dec32); break; case 64: - e = from64(a, b); + e = fromdecx(a, b, tab.t64, dec64); break; + default: + abort(); + return nil; } + if(pp != nil) + *pp = e; + // if no characters parsed, there wasn't a number to convert if(e == a) return nil; - if(pp != nil) - *pp = e; - b->sign = sign; return mpnorm(b); } --- /n/sources/plan9/sys/man/2/mp Sat Jun 14 00:00:00 2025 +++ /sys/man/2/mp Tue Jun 23 00:00:00 2026 @@ -343,7 +343,17 @@ skips any leading spaces or tabs. .IR Strtomp 's scan stops when encountering a digit not valid in the -base. If +base. +If +.I base +is zero then C-style prefixes select the base: +.B 0x +for hexadecimal, +.B 0b +for binary and +.B 0 +for octal. Otherwise decimal is assumed. +If .I rptr is not zero, .I *rptr