96e8bd5f373713915c8ef70c25efb7aa228720d8
[perl.git] / do / pack
1 void
2 do_pack(TARG,arglast)
3 register STR *TARG;
4 int *arglast;
5 {
6     register STR **st = stack->ary_array;
7     register int sp = arglast[1];
8     register int items;
9     register char *pat = str_get(st[sp]);
10     register char *patend = pat + st[sp]->str_cur;
11     register int len;
12     int datumtype;
13     STR *fromstr;
14     /*SUPPRESS 442*/
15     static char *null10 = "\0\0\0\0\0\0\0\0\0\0";
16     static char *space10 = "          ";
17
18     /* These must not be in registers: */
19     char achar;
20     short ashort;
21     int aint;
22     unsigned int auint;
23     long along;
24     unsigned long aulong;
25 #ifdef QUAD
26     quad aquad;
27     unsigned quad auquad;
28 #endif
29     char *aptr;
30     float afloat;
31     double adouble;
32
33     items = arglast[2] - sp;
34     st += ++sp;
35     str_nset(TARG,"",0);
36     while (pat < patend) {
37 #define NEXTFROM (items-- > 0 ? *st++ : &str_no)
38         datumtype = *pat++;
39         if (*pat == '*') {
40             len = index("@Xxu",datumtype) ? 0 : items;
41             pat++;
42         }
43         else if (isDIGIT(*pat)) {
44             len = *pat++ - '0';
45             while (isDIGIT(*pat))
46                 len = (len * 10) + (*pat++ - '0');
47         }
48         else
49             len = 1;
50         switch(datumtype) {
51         default:
52             break;
53         case '%':
54             fatal("% may only be used in unpack");
55         case '@':
56             len -= TARG->str_cur;
57             if (len > 0)
58                 goto grow;
59             len = -len;
60             if (len > 0)
61                 goto shrink;
62             break;
63         case 'X':
64           shrink:
65             if (TARG->str_cur < len)
66                 fatal("X outside of string");
67             TARG->str_cur -= len;
68             TARG->str_ptr[TARG->str_cur] = '\0';
69             break;
70         case 'x':
71           grow:
72             while (len >= 10) {
73                 str_ncat(TARG,null10,10);
74                 len -= 10;
75             }
76             str_ncat(TARG,null10,len);
77             break;
78         case 'A':
79         case 'a':
80             fromstr = NEXTFROM;
81             aptr = str_get(fromstr);
82             if (pat[-1] == '*')
83                 len = fromstr->str_cur;
84             if (fromstr->str_cur > len)
85                 str_ncat(TARG,aptr,len);
86             else {
87                 str_ncat(TARG,aptr,fromstr->str_cur);
88                 len -= fromstr->str_cur;
89                 if (datumtype == 'A') {
90                     while (len >= 10) {
91                         str_ncat(TARG,space10,10);
92                         len -= 10;
93                     }
94                     str_ncat(TARG,space10,len);
95                 }
96                 else {
97                     while (len >= 10) {
98                         str_ncat(TARG,null10,10);
99                         len -= 10;
100                     }
101                     str_ncat(TARG,null10,len);
102                 }
103             }
104             break;
105         case 'B':
106         case 'b':
107             {
108                 char *savepat = pat;
109                 int saveitems;
110
111                 fromstr = NEXTFROM;
112                 saveitems = items;
113                 aptr = str_get(fromstr);
114                 if (pat[-1] == '*')
115                     len = fromstr->str_cur;
116                 pat = aptr;
117                 aint = TARG->str_cur;
118                 TARG->str_cur += (len+7)/8;
119                 STR_GROW(TARG, TARG->str_cur + 1);
120                 aptr = TARG->str_ptr + aint;
121                 if (len > fromstr->str_cur)
122                     len = fromstr->str_cur;
123                 aint = len;
124                 items = 0;
125                 if (datumtype == 'B') {
126                     for (len = 0; len++ < aint;) {
127                         items |= *pat++ & 1;
128                         if (len & 7)
129                             items <<= 1;
130                         else {
131                             *aptr++ = items & 0xff;
132                             items = 0;
133                         }
134                     }
135                 }
136                 else {
137                     for (len = 0; len++ < aint;) {
138                         if (*pat++ & 1)
139                             items |= 128;
140                         if (len & 7)
141                             items >>= 1;
142                         else {
143                             *aptr++ = items & 0xff;
144                             items = 0;
145                         }
146                     }
147                 }
148                 if (aint & 7) {
149                     if (datumtype == 'B')
150                         items <<= 7 - (aint & 7);
151                     else
152                         items >>= 7 - (aint & 7);
153                     *aptr++ = items & 0xff;
154                 }
155                 pat = TARG->str_ptr + TARG->str_cur;
156                 while (aptr <= pat)
157                     *aptr++ = '\0';
158
159                 pat = savepat;
160                 items = saveitems;
161             }
162             break;
163         case 'H':
164         case 'h':
165             {
166                 char *savepat = pat;
167                 int saveitems;
168
169                 fromstr = NEXTFROM;
170                 saveitems = items;
171                 aptr = str_get(fromstr);
172                 if (pat[-1] == '*')
173                     len = fromstr->str_cur;
174                 pat = aptr;
175                 aint = TARG->str_cur;
176                 TARG->str_cur += (len+1)/2;
177                 STR_GROW(TARG, TARG->str_cur + 1);
178                 aptr = TARG->str_ptr + aint;
179                 if (len > fromstr->str_cur)
180                     len = fromstr->str_cur;
181                 aint = len;
182                 items = 0;
183                 if (datumtype == 'H') {
184                     for (len = 0; len++ < aint;) {
185                         if (isALPHA(*pat))
186                             items |= ((*pat++ & 15) + 9) & 15;
187                         else
188                             items |= *pat++ & 15;
189                         if (len & 1)
190                             items <<= 4;
191                         else {
192                             *aptr++ = items & 0xff;
193                             items = 0;
194                         }
195                     }
196                 }
197                 else {
198                     for (len = 0; len++ < aint;) {
199                         if (isALPHA(*pat))
200                             items |= (((*pat++ & 15) + 9) & 15) << 4;
201                         else
202                             items |= (*pat++ & 15) << 4;
203                         if (len & 1)
204                             items >>= 4;
205                         else {
206                             *aptr++ = items & 0xff;
207                             items = 0;
208                         }
209                     }
210                 }
211                 if (aint & 1)
212                     *aptr++ = items & 0xff;
213                 pat = TARG->str_ptr + TARG->str_cur;
214                 while (aptr <= pat)
215                     *aptr++ = '\0';
216
217                 pat = savepat;
218                 items = saveitems;
219             }
220             break;
221         case 'C':
222         case 'c':
223             while (len-- > 0) {
224                 fromstr = NEXTFROM;
225                 aint = (int)str_gnum(fromstr);
226                 achar = aint;
227                 str_ncat(TARG,&achar,sizeof(char));
228             }
229             break;
230         /* Float and double added by gnb@melba.bby.oz.au  22/11/89 */
231         case 'f':
232         case 'F':
233             while (len-- > 0) {
234                 fromstr = NEXTFROM;
235                 afloat = (float)str_gnum(fromstr);
236                 str_ncat(TARG, (char *)&afloat, sizeof (float));
237             }
238             break;
239         case 'd':
240         case 'D':
241             while (len-- > 0) {
242                 fromstr = NEXTFROM;
243                 adouble = (double)str_gnum(fromstr);
244                 str_ncat(TARG, (char *)&adouble, sizeof (double));
245             }
246             break;
247         case 'n':
248             while (len-- > 0) {
249                 fromstr = NEXTFROM;
250                 ashort = (short)str_gnum(fromstr);
251 #ifdef HAS_HTONS
252                 ashort = htons(ashort);
253 #endif
254                 str_ncat(TARG,(char*)&ashort,sizeof(short));
255             }
256             break;
257         case 'v':
258             while (len-- > 0) {
259                 fromstr = NEXTFROM;
260                 ashort = (short)str_gnum(fromstr);
261 #ifdef HAS_HTOVS
262                 ashort = htovs(ashort);
263 #endif
264                 str_ncat(TARG,(char*)&ashort,sizeof(short));
265             }
266             break;
267         case 'S':
268         case 's':
269             while (len-- > 0) {
270                 fromstr = NEXTFROM;
271                 ashort = (short)str_gnum(fromstr);
272                 str_ncat(TARG,(char*)&ashort,sizeof(short));
273             }
274             break;
275         case 'I':
276             while (len-- > 0) {
277                 fromstr = NEXTFROM;
278                 auint = U_I(str_gnum(fromstr));
279                 str_ncat(TARG,(char*)&auint,sizeof(unsigned int));
280             }
281             break;
282         case 'i':
283             while (len-- > 0) {
284                 fromstr = NEXTFROM;
285                 aint = (int)str_gnum(fromstr);
286                 str_ncat(TARG,(char*)&aint,sizeof(int));
287             }
288             break;
289         case 'N':
290             while (len-- > 0) {
291                 fromstr = NEXTFROM;
292                 aulong = U_L(str_gnum(fromstr));
293 #ifdef HAS_HTONL
294                 aulong = htonl(aulong);
295 #endif
296                 str_ncat(TARG,(char*)&aulong,sizeof(unsigned long));
297             }
298             break;
299         case 'V':
300             while (len-- > 0) {
301                 fromstr = NEXTFROM;
302                 aulong = U_L(str_gnum(fromstr));
303 #ifdef HAS_HTOVL
304                 aulong = htovl(aulong);
305 #endif
306                 str_ncat(TARG,(char*)&aulong,sizeof(unsigned long));
307             }
308             break;
309         case 'L':
310             while (len-- > 0) {
311                 fromstr = NEXTFROM;
312                 aulong = U_L(str_gnum(fromstr));
313                 str_ncat(TARG,(char*)&aulong,sizeof(unsigned long));
314             }
315             break;
316         case 'l':
317             while (len-- > 0) {
318                 fromstr = NEXTFROM;
319                 along = (long)str_gnum(fromstr);
320                 str_ncat(TARG,(char*)&along,sizeof(long));
321             }
322             break;
323 #ifdef QUAD
324         case 'Q':
325             while (len-- > 0) {
326                 fromstr = NEXTFROM;
327                 auquad = (unsigned quad)str_gnum(fromstr);
328                 str_ncat(TARG,(char*)&auquad,sizeof(unsigned quad));
329             }
330             break;
331         case 'q':
332             while (len-- > 0) {
333                 fromstr = NEXTFROM;
334                 aquad = (quad)str_gnum(fromstr);
335                 str_ncat(TARG,(char*)&aquad,sizeof(quad));
336             }
337             break;
338 #endif /* QUAD */
339         case 'p':
340             while (len-- > 0) {
341                 fromstr = NEXTFROM;
342                 aptr = str_get(fromstr);
343                 str_ncat(TARG,(char*)&aptr,sizeof(char*));
344             }
345             break;
346         case 'u':
347             fromstr = NEXTFROM;
348             aptr = str_get(fromstr);
349             aint = fromstr->str_cur;
350             STR_GROW(TARG,aint * 4 / 3);
351             if (len <= 1)
352                 len = 45;
353             else
354                 len = len / 3 * 3;
355             while (aint > 0) {
356                 int todo;
357
358                 if (aint > len)
359                     todo = len;
360                 else
361                     todo = aint;
362                 doencodes(TARG, aptr, todo);
363                 aint -= todo;
364                 aptr += todo;
365             }
366             break;
367         }
368     }
369     STABSET(TARG);
370 }
371 #undef NEXTFROM
372
373 static void
374 doencodes(TARG, s, len)
375 register STR *TARG;
376 register char *s;
377 register int len;
378 {
379     char hunk[5];
380
381     *hunk = len + ' ';
382     str_ncat(TARG, hunk, 1);
383     hunk[4] = '\0';
384     while (len > 0) {
385         hunk[0] = ' ' + (077 & (*s >> 2));
386         hunk[1] = ' ' + (077 & ((*s << 4) & 060 | (s[1] >> 4) & 017));
387         hunk[2] = ' ' + (077 & ((s[1] << 2) & 074 | (s[2] >> 6) & 03));
388         hunk[3] = ' ' + (077 & (s[2] & 077));
389         str_ncat(TARG, hunk, 4);
390         s += 3;
391         len -= 3;
392     }
393     for (s = TARG->str_ptr; *s; s++) {
394         if (*s == ' ')
395             *s = '`';
396     }
397     str_ncat(TARG, "\n", 1);
398 }
399