This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perl 5.0 alpha 2
[perl5.git] / do / sprintf
1 void
2 do_sprintf(TARG,len,sarg)
3 register STR *TARG;
4 register int len;
5 register STR **sarg;
6 {
7     register char *s;
8     register char *t;
9     register char *f;
10     bool dolong;
11 #ifdef QUAD
12     bool doquad;
13 #endif /* QUAD */
14     char ch;
15     register char *send;
16     register STR *arg;
17     char *xs;
18     int xlen;
19     int pre;
20     int post;
21     double value;
22
23     str_set(TARG,"");
24     len--;                      /* don't count pattern string */
25     t = s = str_get(*sarg);
26     send = s + (*sarg)->str_cur;
27     sarg++;
28     for ( ; ; len--) {
29
30         /*SUPPRESS 560*/
31         if (len <= 0 || !(arg = *sarg++))
32             arg = &str_no;
33
34         /*SUPPRESS 530*/
35         for ( ; t < send && *t != '%'; t++) ;
36         if (t >= send)
37             break;              /* end of format string, ignore extra args */
38         f = t;
39         *buf = '\0';
40         xs = buf;
41 #ifdef QUAD
42         doquad =
43 #endif /* QUAD */
44         dolong = FALSE;
45         pre = post = 0;
46         for (t++; t < send; t++) {
47             switch (*t) {
48             default:
49                 ch = *(++t);
50                 *t = '\0';
51                 (void)sprintf(xs,f);
52                 len++, sarg--;
53                 xlen = strlen(xs);
54                 break;
55             case '0': case '1': case '2': case '3': case '4':
56             case '5': case '6': case '7': case '8': case '9': 
57             case '.': case '#': case '-': case '+': case ' ':
58                 continue;
59             case 'l':
60 #ifdef QUAD
61                 if (dolong) {
62                     dolong = FALSE;
63                     doquad = TRUE;
64                 } else
65 #endif
66                 dolong = TRUE;
67                 continue;
68             case 'c':
69                 ch = *(++t);
70                 *t = '\0';
71                 xlen = (int)str_gnum(arg);
72                 if (strEQ(f,"%c")) { /* some printfs fail on null chars */
73                     *xs = xlen;
74                     xs[1] = '\0';
75                     xlen = 1;
76                 }
77                 else {
78                     (void)sprintf(xs,f,xlen);
79                     xlen = strlen(xs);
80                 }
81                 break;
82             case 'D':
83                 dolong = TRUE;
84                 /* FALL THROUGH */
85             case 'd':
86                 ch = *(++t);
87                 *t = '\0';
88 #ifdef QUAD
89                 if (doquad)
90                     (void)sprintf(buf,s,(quad)str_gnum(arg));
91                 else
92 #endif
93                 if (dolong)
94                     (void)sprintf(xs,f,(long)str_gnum(arg));
95                 else
96                     (void)sprintf(xs,f,(int)str_gnum(arg));
97                 xlen = strlen(xs);
98                 break;
99             case 'X': case 'O':
100                 dolong = TRUE;
101                 /* FALL THROUGH */
102             case 'x': case 'o': case 'u':
103                 ch = *(++t);
104                 *t = '\0';
105                 value = str_gnum(arg);
106 #ifdef QUAD
107                 if (doquad)
108                     (void)sprintf(buf,s,(unsigned quad)value);
109                 else
110 #endif
111                 if (dolong)
112                     (void)sprintf(xs,f,U_L(value));
113                 else
114                     (void)sprintf(xs,f,U_I(value));
115                 xlen = strlen(xs);
116                 break;
117             case 'E': case 'e': case 'f': case 'G': case 'g':
118                 ch = *(++t);
119                 *t = '\0';
120                 (void)sprintf(xs,f,str_gnum(arg));
121                 xlen = strlen(xs);
122                 break;
123             case 's':
124                 ch = *(++t);
125                 *t = '\0';
126                 xs = str_get(arg);
127                 xlen = arg->str_cur;
128                 if (*xs == 'S' && xs[1] == 't' && xs[2] == 'B' && xs[3] == '\0'
129                   && xlen == sizeof(STBP)) {
130                     STR *tmpstr = Str_new(24,0);
131
132                     stab_efullname(tmpstr, ((STAB*)arg)); /* a stab value! */
133                     sprintf(tokenbuf,"*%s",tmpstr->str_ptr);
134                                         /* reformat to non-binary */
135                     xs = tokenbuf;
136                     xlen = strlen(tokenbuf);
137                     str_free(tmpstr);
138                 }
139                 if (strEQ(f,"%s")) {    /* some printfs fail on >128 chars */
140                     break;              /* so handle simple cases */
141                 }
142                 else if (f[1] == '-') {
143                     char *mp = index(f, '.');
144                     int min = atoi(f+2);
145
146                     if (mp) {
147                         int max = atoi(mp+1);
148
149                         if (xlen > max)
150                             xlen = max;
151                     }
152                     if (xlen < min)
153                         post = min - xlen;
154                     break;
155                 }
156                 else if (isDIGIT(f[1])) {
157                     char *mp = index(f, '.');
158                     int min = atoi(f+1);
159
160                     if (mp) {
161                         int max = atoi(mp+1);
162
163                         if (xlen > max)
164                             xlen = max;
165                     }
166                     if (xlen < min)
167                         pre = min - xlen;
168                     break;
169                 }
170                 strcpy(tokenbuf+64,f);  /* sprintf($s,...$s...) */
171                 *t = ch;
172                 (void)sprintf(buf,tokenbuf+64,xs);
173                 xs = buf;
174                 xlen = strlen(xs);
175                 break;
176             }
177             /* end of switch, copy results */
178             *t = ch;
179             STR_GROW(TARG, TARG->str_cur + (f - s) + xlen + 1 + pre + post);
180             str_ncat(TARG, s, f - s);
181             if (pre) {
182                 repeatcpy(TARG->str_ptr + TARG->str_cur, " ", 1, pre);
183                 TARG->str_cur += pre;
184             }
185             str_ncat(TARG, xs, xlen);
186             if (post) {
187                 repeatcpy(TARG->str_ptr + TARG->str_cur, " ", 1, post);
188                 TARG->str_cur += post;
189             }
190             s = t;
191             break;              /* break from for loop */
192         }
193     }
194     str_ncat(TARG, s, t - s);
195     STABSET(TARG);
196 }
197