summaryrefslogtreecommitdiff
path: root/do/unpack
diff options
context:
space:
mode:
Diffstat (limited to 'do/unpack')
-rw-r--r--do/unpack561
1 files changed, 561 insertions, 0 deletions
diff --git a/do/unpack b/do/unpack
new file mode 100644
index 0000000000..81cca11656
--- /dev/null
+++ b/do/unpack
@@ -0,0 +1,561 @@
+int
+do_unpack(TARG,gimme,arglast)
+STR *TARG;
+int gimme;
+int *arglast;
+{
+ STR **st = stack->ary_array;
+ register int sp = arglast[0] + 1;
+ register char *pat = str_get(st[sp++]);
+ register char *s = str_get(st[sp]);
+ char *strend = s + st[sp--]->str_cur;
+ char *strbeg = s;
+ register char *patend = pat + st[sp]->str_cur;
+ int datumtype;
+ register int len;
+ register int bits;
+
+ /* These must not be in registers: */
+ short ashort;
+ int aint;
+ long along;
+#ifdef QUAD
+ quad aquad;
+#endif
+ unsigned short aushort;
+ unsigned int auint;
+ unsigned long aulong;
+#ifdef QUAD
+ unsigned quad auquad;
+#endif
+ char *aptr;
+ float afloat;
+ double adouble;
+ int checksum = 0;
+ unsigned long culong;
+ double cdouble;
+
+ if (gimme != G_ARRAY) { /* arrange to do first one only */
+ /*SUPPRESS 530*/
+ for (patend = pat; !isALPHA(*patend) || *patend == 'x'; patend++) ;
+ if (index("aAbBhH", *patend) || *pat == '%') {
+ patend++;
+ while (isDIGIT(*patend) || *patend == '*')
+ patend++;
+ }
+ else
+ patend++;
+ }
+ sp--;
+ while (pat < patend) {
+ reparse:
+ datumtype = *pat++;
+ if (pat >= patend)
+ len = 1;
+ else if (*pat == '*') {
+ len = strend - strbeg; /* long enough */
+ pat++;
+ }
+ else if (isDIGIT(*pat)) {
+ len = *pat++ - '0';
+ while (isDIGIT(*pat))
+ len = (len * 10) + (*pat++ - '0');
+ }
+ else
+ len = (datumtype != '@');
+ switch(datumtype) {
+ default:
+ break;
+ case '%':
+ if (len == 1 && pat[-1] != '1')
+ len = 16;
+ checksum = len;
+ culong = 0;
+ cdouble = 0;
+ if (pat < patend)
+ goto reparse;
+ break;
+ case '@':
+ if (len > strend - strbeg)
+ fatal("@ outside of string");
+ s = strbeg + len;
+ break;
+ case 'X':
+ if (len > s - strbeg)
+ fatal("X outside of string");
+ s -= len;
+ break;
+ case 'x':
+ if (len > strend - s)
+ fatal("x outside of string");
+ s += len;
+ break;
+ case 'A':
+ case 'a':
+ if (len > strend - s)
+ len = strend - s;
+ if (checksum)
+ goto uchar_checksum;
+ TARG = Str_new(35,len);
+ str_nset(TARG,s,len);
+ s += len;
+ if (datumtype == 'A') {
+ aptr = s; /* borrow register */
+ s = TARG->str_ptr + len - 1;
+ while (s >= TARG->str_ptr && (!*s || isSPACE(*s)))
+ s--;
+ *++s = '\0';
+ TARG->str_cur = s - TARG->str_ptr;
+ s = aptr; /* unborrow register */
+ }
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ break;
+ case 'B':
+ case 'b':
+ if (pat[-1] == '*' || len > (strend - s) * 8)
+ len = (strend - s) * 8;
+ TARG = Str_new(35, len + 1);
+ TARG->str_cur = len;
+ TARG->str_pok = 1;
+ aptr = pat; /* borrow register */
+ pat = TARG->str_ptr;
+ if (datumtype == 'b') {
+ aint = len;
+ for (len = 0; len < aint; len++) {
+ if (len & 7) /*SUPPRESS 595*/
+ bits >>= 1;
+ else
+ bits = *s++;
+ *pat++ = '0' + (bits & 1);
+ }
+ }
+ else {
+ aint = len;
+ for (len = 0; len < aint; len++) {
+ if (len & 7)
+ bits <<= 1;
+ else
+ bits = *s++;
+ *pat++ = '0' + ((bits & 128) != 0);
+ }
+ }
+ *pat = '\0';
+ pat = aptr; /* unborrow register */
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ break;
+ case 'H':
+ case 'h':
+ if (pat[-1] == '*' || len > (strend - s) * 2)
+ len = (strend - s) * 2;
+ TARG = Str_new(35, len + 1);
+ TARG->str_cur = len;
+ TARG->str_pok = 1;
+ aptr = pat; /* borrow register */
+ pat = TARG->str_ptr;
+ if (datumtype == 'h') {
+ aint = len;
+ for (len = 0; len < aint; len++) {
+ if (len & 1)
+ bits >>= 4;
+ else
+ bits = *s++;
+ *pat++ = hexdigit[bits & 15];
+ }
+ }
+ else {
+ aint = len;
+ for (len = 0; len < aint; len++) {
+ if (len & 1)
+ bits <<= 4;
+ else
+ bits = *s++;
+ *pat++ = hexdigit[(bits >> 4) & 15];
+ }
+ }
+ *pat = '\0';
+ pat = aptr; /* unborrow register */
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ break;
+ case 'c':
+ if (len > strend - s)
+ len = strend - s;
+ if (checksum) {
+ while (len-- > 0) {
+ aint = *s++;
+ if (aint >= 128) /* fake up signed chars */
+ aint -= 256;
+ culong += aint;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ aint = *s++;
+ if (aint >= 128) /* fake up signed chars */
+ aint -= 256;
+ TARG = Str_new(36,0);
+ str_numset(TARG,(double)aint);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ }
+ break;
+ case 'C':
+ if (len > strend - s)
+ len = strend - s;
+ if (checksum) {
+ uchar_checksum:
+ while (len-- > 0) {
+ auint = *s++ & 255;
+ culong += auint;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ auint = *s++ & 255;
+ TARG = Str_new(37,0);
+ str_numset(TARG,(double)auint);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ }
+ break;
+ case 's':
+ along = (strend - s) / sizeof(short);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s,&ashort,1,short);
+ s += sizeof(short);
+ culong += ashort;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s,&ashort,1,short);
+ s += sizeof(short);
+ TARG = Str_new(38,0);
+ str_numset(TARG,(double)ashort);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ }
+ break;
+ case 'v':
+ case 'n':
+ case 'S':
+ along = (strend - s) / sizeof(unsigned short);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s,&aushort,1,unsigned short);
+ s += sizeof(unsigned short);
+#ifdef HAS_NTOHS
+ if (datumtype == 'n')
+ aushort = ntohs(aushort);
+#endif
+#ifdef HAS_VTOHS
+ if (datumtype == 'v')
+ aushort = vtohs(aushort);
+#endif
+ culong += aushort;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s,&aushort,1,unsigned short);
+ s += sizeof(unsigned short);
+ TARG = Str_new(39,0);
+#ifdef HAS_NTOHS
+ if (datumtype == 'n')
+ aushort = ntohs(aushort);
+#endif
+#ifdef HAS_VTOHS
+ if (datumtype == 'v')
+ aushort = vtohs(aushort);
+#endif
+ str_numset(TARG,(double)aushort);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ }
+ break;
+ case 'i':
+ along = (strend - s) / sizeof(int);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s,&aint,1,int);
+ s += sizeof(int);
+ if (checksum > 32)
+ cdouble += (double)aint;
+ else
+ culong += aint;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s,&aint,1,int);
+ s += sizeof(int);
+ TARG = Str_new(40,0);
+ str_numset(TARG,(double)aint);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ }
+ break;
+ case 'I':
+ along = (strend - s) / sizeof(unsigned int);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s,&auint,1,unsigned int);
+ s += sizeof(unsigned int);
+ if (checksum > 32)
+ cdouble += (double)auint;
+ else
+ culong += auint;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s,&auint,1,unsigned int);
+ s += sizeof(unsigned int);
+ TARG = Str_new(41,0);
+ str_numset(TARG,(double)auint);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ }
+ break;
+ case 'l':
+ along = (strend - s) / sizeof(long);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s,&along,1,long);
+ s += sizeof(long);
+ if (checksum > 32)
+ cdouble += (double)along;
+ else
+ culong += along;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s,&along,1,long);
+ s += sizeof(long);
+ TARG = Str_new(42,0);
+ str_numset(TARG,(double)along);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ }
+ break;
+ case 'V':
+ case 'N':
+ case 'L':
+ along = (strend - s) / sizeof(unsigned long);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s,&aulong,1,unsigned long);
+ s += sizeof(unsigned long);
+#ifdef HAS_NTOHL
+ if (datumtype == 'N')
+ aulong = ntohl(aulong);
+#endif
+#ifdef HAS_VTOHL
+ if (datumtype == 'V')
+ aulong = vtohl(aulong);
+#endif
+ if (checksum > 32)
+ cdouble += (double)aulong;
+ else
+ culong += aulong;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s,&aulong,1,unsigned long);
+ s += sizeof(unsigned long);
+ TARG = Str_new(43,0);
+#ifdef HAS_NTOHL
+ if (datumtype == 'N')
+ aulong = ntohl(aulong);
+#endif
+#ifdef HAS_VTOHL
+ if (datumtype == 'V')
+ aulong = vtohl(aulong);
+#endif
+ str_numset(TARG,(double)aulong);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ }
+ break;
+ case 'p':
+ along = (strend - s) / sizeof(char*);
+ if (len > along)
+ len = along;
+ while (len-- > 0) {
+ if (sizeof(char*) > strend - s)
+ break;
+ else {
+ Copy(s,&aptr,1,char*);
+ s += sizeof(char*);
+ }
+ TARG = Str_new(44,0);
+ if (aptr)
+ str_set(TARG,aptr);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ break;
+#ifdef QUAD
+ case 'q':
+ while (len-- > 0) {
+ if (s + sizeof(quad) > strend)
+ aquad = 0;
+ else {
+ Copy(s,&aquad,1,quad);
+ s += sizeof(quad);
+ }
+ TARG = Str_new(42,0);
+ str_numset(TARG,(double)aquad);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ break;
+ case 'Q':
+ while (len-- > 0) {
+ if (s + sizeof(unsigned quad) > strend)
+ auquad = 0;
+ else {
+ Copy(s,&auquad,1,unsigned quad);
+ s += sizeof(unsigned quad);
+ }
+ TARG = Str_new(43,0);
+ str_numset(TARG,(double)auquad);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ break;
+#endif
+ /* float and double added gnb@melba.bby.oz.au 22/11/89 */
+ case 'f':
+ case 'F':
+ along = (strend - s) / sizeof(float);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s, &afloat,1, float);
+ s += sizeof(float);
+ cdouble += afloat;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s, &afloat,1, float);
+ s += sizeof(float);
+ TARG = Str_new(47, 0);
+ str_numset(TARG, (double)afloat);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ }
+ break;
+ case 'd':
+ case 'D':
+ along = (strend - s) / sizeof(double);
+ if (len > along)
+ len = along;
+ if (checksum) {
+ while (len-- > 0) {
+ Copy(s, &adouble,1, double);
+ s += sizeof(double);
+ cdouble += adouble;
+ }
+ }
+ else {
+ while (len-- > 0) {
+ Copy(s, &adouble,1, double);
+ s += sizeof(double);
+ TARG = Str_new(48, 0);
+ str_numset(TARG, (double)adouble);
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ }
+ }
+ break;
+ case 'u':
+ along = (strend - s) * 3 / 4;
+ TARG = Str_new(42,along);
+ while (s < strend && *s > ' ' && *s < 'a') {
+ int a,b,c,d;
+ char hunk[4];
+
+ hunk[3] = '\0';
+ len = (*s++ - ' ') & 077;
+ while (len > 0) {
+ if (s < strend && *s >= ' ')
+ a = (*s++ - ' ') & 077;
+ else
+ a = 0;
+ if (s < strend && *s >= ' ')
+ b = (*s++ - ' ') & 077;
+ else
+ b = 0;
+ if (s < strend && *s >= ' ')
+ c = (*s++ - ' ') & 077;
+ else
+ c = 0;
+ if (s < strend && *s >= ' ')
+ d = (*s++ - ' ') & 077;
+ else
+ d = 0;
+ hunk[0] = a << 2 | b >> 4;
+ hunk[1] = b << 4 | c >> 2;
+ hunk[2] = c << 6 | d;
+ str_ncat(TARG,hunk, len > 3 ? 3 : len);
+ len -= 3;
+ }
+ if (*s == '\n')
+ s++;
+ else if (s[1] == '\n') /* possible checksum byte */
+ s += 2;
+ }
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ break;
+ }
+ if (checksum) {
+ TARG = Str_new(42,0);
+ if (index("fFdD", datumtype) ||
+ (checksum > 32 && index("iIlLN", datumtype)) ) {
+ double modf();
+ double trouble;
+
+ adouble = 1.0;
+ while (checksum >= 16) {
+ checksum -= 16;
+ adouble *= 65536.0;
+ }
+ while (checksum >= 4) {
+ checksum -= 4;
+ adouble *= 16.0;
+ }
+ while (checksum--)
+ adouble *= 2.0;
+ along = (1 << checksum) - 1;
+ while (cdouble < 0.0)
+ cdouble += adouble;
+ cdouble = modf(cdouble / adouble, &trouble) * adouble;
+ str_numset(TARG,cdouble);
+ }
+ else {
+ if (checksum < 32) {
+ along = (1 << checksum) - 1;
+ culong &= (unsigned long)along;
+ }
+ str_numset(TARG,(double)culong);
+ }
+ (void)astore(stack, ++sp, str_2mortal(TARG));
+ checksum = 0;
+ }
+ }
+ return sp;
+}
+