xref: /dragonfly/usr.bin/indent/indent.c (revision 978e8d968759a678190d6705edbb5c1465672add)
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 1985 Sun Microsystems, Inc.
5  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
6  * Copyright (c) 1980, 1993
7  *        The Regents of the University of California.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)indent.c     5.17 (Berkeley) 6/7/93
34  * $FreeBSD: head/usr.bin/indent/indent.c 340138 2018-11-04 19:24:49Z oshogbo $
35  */
36 
37 #include <sys/param.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include "indent_globs.h"
47 #include "indent_codes.h"
48 #include "indent.h"
49 
50 /* Globals */
51 FILE      *input, *output;
52 char      *labbuf, *s_lab, *e_lab, *l_lab;
53 char      *codebuf, *s_code, *e_code, *l_code;
54 char      *combuf, *s_com, *e_com, *l_com;
55 char      *tokenbuf, *s_token, *e_token, *l_token;
56 char      *in_buffer, *in_buffer_limit;
57 char      *buf_ptr, *buf_end;
58 
59 char       sc_buf[sc_size];
60 
61 char      *save_com, *sc_end;
62 char      *bp_save;
63 char      *be_save;
64 
65 struct options                opt;
66 int        line_no;
67 
68 struct parser_state ps;
69 int        ifdef_level;
70 struct parser_state state_stack[5];
71 struct parser_state match_state[5];
72 
73 
74 static void bakcopy(void);
75 static void indent_declaration(int, int);
76 
77 const char *in_name = "Standard Input"; /* will always point to name of input
78                                                    * file */
79 const char *out_name = "Standard Output";         /* will always point to name
80                                                              * of output file */
81 const char *simple_backup_suffix = ".BAK";        /* Suffix to use for backup
82                                                              * files */
83 char        bakfile[MAXPATHLEN] = "";
84 
85 int
main(int argc,char ** argv)86 main(int argc, char **argv)
87 {
88     int         dec_ind;      /* current indentation for declarations */
89     int         di_stack[20]; /* a stack of structure indentation levels */
90     int         force_nl;     /* when true, code must be broken */
91     int         hd_type = 0;  /* used to store type of stmt for if (...),
92                                          * for (...), etc */
93     int             i;                  /* local loop counter */
94     int         scase;                  /* set to true when we see a case, so we will
95                                          * know what to do with the following colon */
96     int         sp_sw;                  /* when true, we are in the expression of
97                                          * if(...), while(...), etc. */
98     int         squest;                 /* when this is positive, we have seen a ?
99                                          * without the matching : in a <c>?<s>:<s>
100                                          * construct */
101     const char *t_ptr;                  /* used for copying tokens */
102     int             tabs_to_var;        /* true if using tabs to indent to var name */
103     int         type_code;    /* the type of token, returned by lexi */
104 
105     int         last_else = 0;          /* true iff last keyword was an else */
106     const char *profile_name = NULL;
107     const char *envval = NULL;
108     struct parser_state transient_state; /* a copy for lookup */
109 
110     /*-----------------------------------------------*\
111     |                     INITIALIZATION                          |
112     \*-----------------------------------------------*/
113 
114     found_err = 0;
115 
116     ps.p_stack[0] = stmt;     /* this is the parser's stack */
117     ps.last_nl = true;                  /* this is true if the last thing scanned was
118                                          * a newline */
119     ps.last_token = semicolon;
120     combuf = (char *) malloc(bufsize);
121     if (combuf == NULL)
122           err(1, NULL);
123     labbuf = (char *) malloc(bufsize);
124     if (labbuf == NULL)
125           err(1, NULL);
126     codebuf = (char *) malloc(bufsize);
127     if (codebuf == NULL)
128           err(1, NULL);
129     tokenbuf = (char *) malloc(bufsize);
130     if (tokenbuf == NULL)
131           err(1, NULL);
132     alloc_typenames();
133     init_constant_tt();
134     l_com = combuf + bufsize - 5;
135     l_lab = labbuf + bufsize - 5;
136     l_code = codebuf + bufsize - 5;
137     l_token = tokenbuf + bufsize - 5;
138     combuf[0] = codebuf[0] = labbuf[0] = ' ';     /* set up code, label, and
139                                                              * comment buffers */
140     combuf[1] = codebuf[1] = labbuf[1] = '\0';
141     opt.else_if = 1;                    /* Default else-if special processing to on */
142     s_lab = e_lab = labbuf + 1;
143     s_code = e_code = codebuf + 1;
144     s_com = e_com = combuf + 1;
145     s_token = e_token = tokenbuf + 1;
146 
147     in_buffer = (char *) malloc(10);
148     if (in_buffer == NULL)
149           err(1, NULL);
150     in_buffer_limit = in_buffer + 8;
151     buf_ptr = buf_end = in_buffer;
152     line_no = 1;
153     had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
154     sp_sw = force_nl = false;
155     ps.in_or_st = false;
156     ps.bl_line = true;
157     dec_ind = 0;
158     di_stack[ps.dec_nest = 0] = 0;
159     ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
160 
161     scase = ps.pcase = false;
162     squest = 0;
163     sc_end = NULL;
164     bp_save = NULL;
165     be_save = NULL;
166 
167     output = NULL;
168     tabs_to_var = 0;
169 
170     envval = getenv("SIMPLE_BACKUP_SUFFIX");
171     if (envval)
172         simple_backup_suffix = envval;
173 
174     /*--------------------------------------------------*\
175     |               COMMAND LINE SCAN              |
176     \*--------------------------------------------------*/
177 
178 #ifdef undef
179     max_col = 78;             /* -l78 */
180     lineup_to_parens = 1;     /* -lp */
181     lineup_to_parens_always = 0;        /* -nlpl */
182     ps.ljust_decl = 0;                  /* -ndj */
183     ps.com_ind = 33;                    /* -c33 */
184     star_comment_cont = 1;    /* -sc */
185     ps.ind_size = 8;                    /* -i8 */
186     verbose = 0;
187     ps.decl_indent = 16;      /* -di16 */
188     ps.local_decl_indent = -1;          /* if this is not set to some nonnegative value
189                                          * by an arg, we will set this equal to
190                                          * ps.decl_ind */
191     ps.indent_parameters = 1; /* -ip */
192     ps.decl_com_ind = 0;      /* if this is not set to some positive value
193                                          * by an arg, we will set this equal to
194                                          * ps.com_ind */
195     btype_2 = 1;              /* -br */
196     cuddle_else = 1;                    /* -ce */
197     ps.unindent_displace = 0; /* -d0 */
198     ps.case_indent = 0;                 /* -cli0 */
199     format_block_comments = 1;          /* -fcb */
200     format_col1_comments = 1; /* -fc1 */
201     procnames_start_line = 1; /* -psl */
202     proc_calls_space = 0;     /* -npcs */
203     comment_delimiter_on_blankline = 1; /* -cdb */
204     ps.leave_comma = 1;                 /* -nbc */
205 #endif
206 
207     for (i = 1; i < argc; ++i)
208           if (strcmp(argv[i], "-npro") == 0)
209               break;
210           else if (argv[i][0] == '-' && argv[i][1] == 'P' && argv[i][2] != '\0')
211               profile_name = argv[i];   /* non-empty -P (set profile) */
212     set_defaults();
213     if (i >= argc)
214           set_profile(profile_name);
215 
216     for (i = 1; i < argc; ++i) {
217 
218           /*
219            * look thru args (if any) for changes to defaults
220            */
221           if (argv[i][0] != '-') {      /* no flag on parameter */
222               if (input == NULL) {      /* we must have the input file */
223                     in_name = argv[i];  /* remember name of input file */
224                     input = fopen(in_name, "r");
225                     if (input == NULL)  /* check for open error */
226                               err(1, "%s", in_name);
227                     continue;
228               }
229               else if (output == NULL) {          /* we have the output file */
230                     out_name = argv[i]; /* remember name of output file */
231                     if (strcmp(in_name, out_name) == 0) {   /* attempt to overwrite
232                                                                        * the file */
233                         errx(1, "input and output files must be different");
234                     }
235                     output = fopen(out_name, "w");
236                     if (output == NULL) /* check for create error */
237                               err(1, "%s", out_name);
238                     continue;
239               }
240               errx(1, "unknown parameter: %s", argv[i]);
241           }
242           else
243               set_option(argv[i]);
244     }                                   /* end of for */
245     if (input == NULL)
246           input = stdin;
247     if (output == NULL) {
248           if (input == stdin)
249               output = stdout;
250           else {
251               out_name = in_name;
252               bakcopy();
253           }
254     }
255 
256     if (opt.com_ind <= 1)
257           opt.com_ind = 2;    /* don't put normal comments before column 2 */
258     if (opt.block_comment_max_col <= 0)
259           opt.block_comment_max_col = opt.max_col;
260     if (opt.local_decl_indent < 0) /* if not specified by user, set this */
261           opt.local_decl_indent = opt.decl_indent;
262     if (opt.decl_com_ind <= 0)          /* if not specified by user, set this */
263           opt.decl_com_ind = opt.ljust_decl ? (opt.com_ind <= 10 ? 2 : opt.com_ind - 8) : opt.com_ind;
264     if (opt.continuation_indent == 0)
265           opt.continuation_indent = opt.ind_size;
266     fill_buffer();            /* get first batch of stuff into input buffer */
267 
268     parse(semicolon);
269     {
270           char *p = buf_ptr;
271           int col = 1;
272 
273           while (1) {
274               if (*p == ' ')
275                     col++;
276               else if (*p == '\t')
277                     col = opt.tabsize * (1 + (col - 1) / opt.tabsize) + 1;
278               else
279                     break;
280               p++;
281           }
282           if (col > opt.ind_size)
283               ps.ind_level = ps.i_l_follow = col / opt.ind_size;
284     }
285 
286     /*
287      * START OF MAIN LOOP
288      */
289 
290     while (1) {                         /* this is the main loop.  it will go until we
291                                          * reach eof */
292           int comment_buffered = false;
293 
294           type_code = lexi(&ps);        /* lexi reads one token.  The actual
295                                          * characters read are stored in "token". lexi
296                                          * returns a code indicating the type of token */
297 
298           /*
299            * The following code moves newlines and comments following an if (),
300            * while (), else, etc. up to the start of the following stmt to
301            * a buffer. This allows proper handling of both kinds of brace
302            * placement (-br, -bl) and cuddling "else" (-ce).
303            */
304 
305           while (ps.search_brace) {
306               switch (type_code) {
307               case newline:
308                     if (sc_end == NULL) {
309                         save_com = sc_buf;
310                         save_com[0] = save_com[1] = ' ';
311                         sc_end = &save_com[2];
312                     }
313                     *sc_end++ = '\n';
314                     /*
315                      * We may have inherited a force_nl == true from the previous
316                      * token (like a semicolon). But once we know that a newline
317                      * has been scanned in this loop, force_nl should be false.
318                      *
319                      * However, the force_nl == true must be preserved if newline
320                      * is never scanned in this loop, so this assignment cannot be
321                      * done earlier.
322                      */
323                     force_nl = false;
324               case form_feed:
325                     break;
326               case comment:
327                     if (sc_end == NULL) {
328                         /*
329                          * Copy everything from the start of the line, because
330                          * pr_comment() will use that to calculate original
331                          * indentation of a boxed comment.
332                          */
333                         memcpy(sc_buf, in_buffer, buf_ptr - in_buffer - 4);
334                         save_com = sc_buf + (buf_ptr - in_buffer - 4);
335                         save_com[0] = save_com[1] = ' ';
336                         sc_end = &save_com[2];
337                     }
338                     comment_buffered = true;
339                     *sc_end++ = '/';    /* copy in start of comment */
340                     *sc_end++ = '*';
341                     for (;;) {          /* loop until we get to the end of the comment */
342                         *sc_end = *buf_ptr++;
343                         if (buf_ptr >= buf_end)
344                               fill_buffer();
345                         if (*sc_end++ == '*' && *buf_ptr == '/')
346                               break;    /* we are at end of comment */
347                         if (sc_end >= &save_com[sc_size]) { /* check for temp buffer
348                                                                        * overflow */
349                               diag2(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever");
350                               fflush(output);
351                               exit(1);
352                         }
353                     }
354                     /* FALLTHROUGH */
355                     *sc_end++ = '/';    /* add ending slash */
356                     if (++buf_ptr >= buf_end)     /* get past / in buffer */
357                         fill_buffer();
358                     break;
359               case lbrace:
360                     /*
361                      * Put KNF-style lbraces before the buffered up tokens and
362                      * jump out of this loop in order to avoid copying the token
363                      * again under the default case of the switch below.
364                      */
365                     if (sc_end != NULL && opt.btype_2) {
366                         save_com[0] = '{';
367                         /*
368                          * Originally the lbrace may have been alone on its own
369                          * line, but it will be moved into "the else's line", so
370                          * if there was a newline resulting from the "{" before,
371                          * it must be scanned now and ignored.
372                          */
373                         while (isspace((unsigned char)*buf_ptr)) {
374                               if (++buf_ptr >= buf_end)
375                                   fill_buffer();
376                               if (*buf_ptr == '\n')
377                                   break;
378                         }
379                         goto sw_buffer;
380                     }
381                     /* FALLTHROUGH */
382               default:                  /* it is the start of a normal statement */
383                     {
384                         int remove_newlines;
385 
386                         remove_newlines =
387                               /* "} else" */
388                               (type_code == sp_nparen && *token == 'e' &&
389                                   e_code != s_code && e_code[-1] == '}')
390                               /* "else if" */
391                               || (type_code == sp_paren && *token == 'i' &&
392                                   last_else && opt.else_if);
393                         if (remove_newlines)
394                               force_nl = false;
395                         if (sc_end == NULL) {     /* ignore buffering if
396                                                              * comment wasn't saved up */
397                               ps.search_brace = false;
398                               goto check_type;
399                         }
400                         while (sc_end > save_com && isblank((unsigned char)sc_end[-1])) {
401                               sc_end--;
402                         }
403                         if (opt.swallow_optional_blanklines ||
404                               (!comment_buffered && remove_newlines)) {
405                               force_nl = !remove_newlines;
406                               while (sc_end > save_com && sc_end[-1] == '\n') {
407                                   sc_end--;
408                               }
409                         }
410                         if (force_nl) { /* if we should insert a nl here, put
411                                                    * it into the buffer */
412                               force_nl = false;
413                               --line_no;          /* this will be re-increased when the
414                                                    * newline is read from the buffer */
415                               *sc_end++ = '\n';
416                               *sc_end++ = ' ';
417                               if (opt.verbose) /* print error msg if the line was
418                                                    * not already broken */
419                                   diag2(0, "Line broken");
420                         }
421                         for (t_ptr = token; *t_ptr; ++t_ptr)
422                               *sc_end++ = *t_ptr;
423 
424               sw_buffer:
425                         ps.search_brace = false;  /* stop looking for start of
426                                                              * stmt */
427                         bp_save = buf_ptr;        /* save current input buffer */
428                         be_save = buf_end;
429                         buf_ptr = save_com;       /* fix so that subsequent calls to
430                                                    * lexi will take tokens out of
431                                                    * save_com */
432                         *sc_end++ = ' ';/* add trailing blank, just in case */
433                         buf_end = sc_end;
434                         sc_end = NULL;
435                         break;
436                     }
437               }                         /* end of switch */
438               /*
439                * We must make this check, just in case there was an unexpected
440                * EOF.
441                */
442               if (type_code != 0) {
443                     /*
444                      * The only intended purpose of calling lexi() below is to
445                      * categorize the next token in order to decide whether to
446                      * continue buffering forthcoming tokens. Once the buffering
447                      * is over, lexi() will be called again elsewhere on all of
448                      * the tokens - this time for normal processing.
449                      *
450                      * Calling it for this purpose is a bug, because lexi() also
451                      * changes the parser state and discards leading whitespace,
452                      * which is needed mostly for comment-related considerations.
453                      *
454                      * Work around the former problem by giving lexi() a copy of
455                      * the current parser state and discard it if the call turned
456                      * out to be just a look ahead.
457                      *
458                      * Work around the latter problem by copying all whitespace
459                      * characters into the buffer so that the later lexi() call
460                      * will read them.
461                      */
462                     if (sc_end != NULL) {
463                         while (*buf_ptr == ' ' || *buf_ptr == '\t') {
464                               *sc_end++ = *buf_ptr++;
465                               if (sc_end >= &save_com[sc_size]) {
466                                   errx(1, "input too long");
467                               }
468                         }
469                         if (buf_ptr >= buf_end) {
470                               fill_buffer();
471                         }
472                     }
473                     transient_state = ps;
474                     type_code = lexi(&transient_state);     /* read another token */
475                     if (type_code != newline && type_code != form_feed &&
476                         type_code != comment && !transient_state.search_brace) {
477                         ps = transient_state;
478                     }
479               }
480           }                             /* end of while (search_brace) */
481           last_else = 0;
482 check_type:
483           if (type_code == 0) {         /* we got eof */
484               if (s_lab != e_lab || s_code != e_code
485                         || s_com != e_com)        /* must dump end of line */
486                     dump_line();
487               if (ps.tos > 1) /* check for balanced braces */
488                     diag2(1, "Stuff missing from end of file");
489 
490               if (opt.verbose) {
491                     printf("There were %d output lines and %d comments\n",
492                            ps.out_lines, ps.out_coms);
493                     printf("(Lines with comments)/(Lines with code): %6.3f\n",
494                            (1.0 * ps.com_lines) / code_lines);
495               }
496               fflush(output);
497               exit(found_err);
498           }
499           if (
500                     (type_code != comment) &&
501                     (type_code != newline) &&
502                     (type_code != preesc) &&
503                     (type_code != form_feed)) {
504               if (force_nl &&
505                         (type_code != semicolon) &&
506                         (type_code != lbrace || !opt.btype_2)) {
507                     /* we should force a broken line here */
508                     if (opt.verbose)
509                         diag2(0, "Line broken");
510                     dump_line();
511                     ps.want_blank = false;        /* dont insert blank at line start */
512                     force_nl = false;
513               }
514               ps.in_stmt = true;        /* turn on flag which causes an extra level of
515                                          * indentation. this is turned off by a ; or
516                                          * '}' */
517               if (s_com != e_com) {     /* the turkey has embedded a comment
518                                                    * in a line. fix it */
519                     int len = e_com - s_com;
520 
521                     CHECK_SIZE_CODE(len + 3);
522                     *e_code++ = ' ';
523                     memcpy(e_code, s_com, len);
524                     e_code += len;
525                     *e_code++ = ' ';
526                     *e_code = '\0';     /* null terminate code sect */
527                     ps.want_blank = false;
528                     e_com = s_com;
529               }
530           }
531           else if (type_code != comment)          /* preserve force_nl thru a comment */
532               force_nl = false;         /* cancel forced newline after newline, form
533                                          * feed, etc */
534 
535 
536 
537           /*-----------------------------------------------------*\
538           |            do switch on type of token scanned             |
539           \*-----------------------------------------------------*/
540           CHECK_SIZE_CODE(3); /* maximum number of increments of e_code
541                                          * before the next CHECK_SIZE_CODE or
542                                          * dump_line() is 2. After that there's the
543                                          * final increment for the null character. */
544           switch (type_code) {          /* now, decide what to do with the token */
545 
546           case form_feed:     /* found a form feed in line */
547               ps.use_ff = true;         /* a form feed is treated much like a newline */
548               dump_line();
549               ps.want_blank = false;
550               break;
551 
552           case newline:
553               if (ps.last_token != comma || ps.p_l_follow > 0
554                         || !opt.leave_comma || ps.block_init || !break_comma || s_com != e_com) {
555                     dump_line();
556                     ps.want_blank = false;
557               }
558               ++line_no;                /* keep track of input line number */
559               break;
560 
561           case lparen:                  /* got a '(' or '[' */
562               /* count parens to make Healy happy */
563               if (++ps.p_l_follow == nitems(ps.paren_indents)) {
564                     diag3(0, "Reached internal limit of %d unclosed parens",
565                         nitems(ps.paren_indents));
566                     ps.p_l_follow--;
567               }
568               if (*token == '[')
569                     /* not a function pointer declaration or a function call */;
570               else if (ps.in_decl && !ps.block_init && !ps.dumped_decl_indent &&
571                     ps.procname[0] == '\0' && ps.paren_level == 0) {
572                     /* function pointer declarations */
573                     indent_declaration(dec_ind, tabs_to_var);
574                     ps.dumped_decl_indent = true;
575               }
576               else if (ps.want_blank &&
577                         ((ps.last_token != ident && ps.last_token != funcname) ||
578                         opt.proc_calls_space ||
579                         /* offsetof (1) is never allowed a space; sizeof (2) gets
580                          * one iff -bs; all other keywords (>2) always get a space
581                          * before lparen */
582                               ps.keyword + opt.Bill_Shannon > 2))
583                     *e_code++ = ' ';
584               ps.want_blank = false;
585               *e_code++ = token[0];
586               ps.paren_indents[ps.p_l_follow - 1] = count_spaces_until(1, s_code, e_code) - 1;
587               if (sp_sw && ps.p_l_follow == 1 && opt.extra_expression_indent
588                         && ps.paren_indents[0] < 2 * opt.ind_size)
589                     ps.paren_indents[0] = 2 * opt.ind_size;
590               if (ps.in_or_st && *token == '(' && ps.tos <= 2) {
591                     /*
592                      * this is a kluge to make sure that declarations will be
593                      * aligned right if proc decl has an explicit type on it, i.e.
594                      * "int a(x) {..."
595                      */
596                     parse(semicolon);   /* I said this was a kluge... */
597                     ps.in_or_st = false;          /* turn off flag for structure decl or
598                                                    * initialization */
599               }
600               /* parenthesized type following sizeof or offsetof is not a cast */
601               if (ps.keyword == 1 || ps.keyword == 2)
602                     ps.not_cast_mask |= 1 << ps.p_l_follow;
603               break;
604 
605           case rparen:                  /* got a ')' or ']' */
606               if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.not_cast_mask) {
607                     ps.last_u_d = true;
608                     ps.cast_mask &= (1 << ps.p_l_follow) - 1;
609                     ps.want_blank = opt.space_after_cast;
610               } else
611                     ps.want_blank = true;
612               ps.not_cast_mask &= (1 << ps.p_l_follow) - 1;
613               if (--ps.p_l_follow < 0) {
614                     ps.p_l_follow = 0;
615                     diag3(0, "Extra %c", *token);
616               }
617               if (e_code == s_code)     /* if the paren starts the line */
618                     ps.paren_level = ps.p_l_follow;         /* then indent it */
619 
620               *e_code++ = token[0];
621 
622               if (sp_sw && (ps.p_l_follow == 0)) {          /* check for end of if
623                                                                        * (...), or some such */
624                     sp_sw = false;
625                     force_nl = true;/* must force newline after if */
626                     ps.last_u_d = true; /* inform lexi that a following
627                                                    * operator is unary */
628                     ps.in_stmt = false; /* dont use stmt continuation
629                                                    * indentation */
630 
631                     parse(hd_type);     /* let parser worry about if, or whatever */
632               }
633               ps.search_brace = opt.btype_2; /* this should ensure that
634                                                    * constructs such as main(){...}
635                                                    * and int[]{...} have their braces
636                                                    * put in the right place */
637               break;
638 
639           case unary_op:                /* this could be any unary operation */
640               if (!ps.dumped_decl_indent && ps.in_decl && !ps.block_init &&
641                     ps.procname[0] == '\0' && ps.paren_level == 0) {
642                     /* pointer declarations */
643 
644                     /*
645                      * if this is a unary op in a declaration, we should indent
646                      * this token
647                      */
648                     for (i = 0; token[i]; ++i)
649                         /* find length of token */;
650                     indent_declaration(dec_ind - i, tabs_to_var);
651                     ps.dumped_decl_indent = true;
652               }
653               else if (ps.want_blank)
654                     *e_code++ = ' ';
655 
656               {
657                     int len = e_token - s_token;
658 
659                     CHECK_SIZE_CODE(len);
660                     memcpy(e_code, token, len);
661                     e_code += len;
662               }
663               ps.want_blank = false;
664               break;
665 
666           case binary_op:     /* any binary operation */
667               {
668                     int len = e_token - s_token;
669 
670                     CHECK_SIZE_CODE(len + 1);
671                     if (ps.want_blank)
672                         *e_code++ = ' ';
673                     memcpy(e_code, token, len);
674                     e_code += len;
675               }
676               ps.want_blank = true;
677               break;
678 
679           case postop:                  /* got a trailing ++ or -- */
680               *e_code++ = token[0];
681               *e_code++ = token[1];
682               ps.want_blank = true;
683               break;
684 
685           case question:                /* got a ? */
686               squest++;                 /* this will be used when a later colon
687                                          * appears so we can distinguish the
688                                          * <c>?<n>:<n> construct */
689               if (ps.want_blank)
690                     *e_code++ = ' ';
691               *e_code++ = '?';
692               ps.want_blank = true;
693               break;
694 
695           case casestmt:                /* got word 'case' or 'default' */
696               scase = true;   /* so we can process the later colon properly */
697               goto copy_id;
698 
699           case colon:                   /* got a ':' */
700               if (squest > 0) {         /* it is part of the <c>?<n>: <n> construct */
701                     --squest;
702                     if (ps.want_blank)
703                         *e_code++ = ' ';
704                     *e_code++ = ':';
705                     ps.want_blank = true;
706                     break;
707               }
708               if (ps.in_or_st) {
709                     *e_code++ = ':';
710                     ps.want_blank = false;
711                     break;
712               }
713               ps.in_stmt = false;       /* seeing a label does not imply we are in a
714                                          * stmt */
715               /*
716                * turn everything so far into a label
717                */
718               {
719                     int len = e_code - s_code;
720 
721                     CHECK_SIZE_LAB(len + 3);
722                     memcpy(e_lab, s_code, len);
723                     e_lab += len;
724                     *e_lab++ = ':';
725                     *e_lab = '\0';
726                     e_code = s_code;
727               }
728               force_nl = ps.pcase = scase;        /* ps.pcase will be used by
729                                                              * dump_line to decide how to
730                                                              * indent the label. force_nl
731                                                              * will force a case n: to be
732                                                              * on a line by itself */
733               scase = false;
734               ps.want_blank = false;
735               break;
736 
737           case semicolon:     /* got a ';' */
738               if (ps.dec_nest == 0)
739                     ps.in_or_st = false;/* we are not in an initialization or
740                                              * structure declaration */
741               scase = false;  /* these will only need resetting in an error */
742               squest = 0;
743               if (ps.last_token == rparen)
744                     ps.in_parameter_declaration = 0;
745               ps.cast_mask = 0;
746               ps.not_cast_mask = 0;
747               ps.block_init = 0;
748               ps.block_init_level = 0;
749               ps.just_saw_decl--;
750 
751               if (ps.in_decl && s_code == e_code && !ps.block_init &&
752                     !ps.dumped_decl_indent && ps.paren_level == 0) {
753                     /* indent stray semicolons in declarations */
754                     indent_declaration(dec_ind - 1, tabs_to_var);
755                     ps.dumped_decl_indent = true;
756               }
757 
758               ps.in_decl = (ps.dec_nest > 0);     /* if we were in a first level
759                                                              * structure declaration, we
760                                                              * arent any more */
761 
762               if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) {
763 
764                     /*
765                      * This should be true iff there were unbalanced parens in the
766                      * stmt.  It is a bit complicated, because the semicolon might
767                      * be in a for stmt
768                      */
769                     diag2(1, "Unbalanced parens");
770                     ps.p_l_follow = 0;
771                     if (sp_sw) {        /* this is a check for an if, while, etc. with
772                                          * unbalanced parens */
773                         sp_sw = false;
774                         parse(hd_type); /* dont lose the if, or whatever */
775                     }
776               }
777               *e_code++ = ';';
778               ps.want_blank = true;
779               ps.in_stmt = (ps.p_l_follow > 0);   /* we are no longer in the
780                                                              * middle of a stmt */
781 
782               if (!sp_sw) {   /* if not if for (;;) */
783                     parse(semicolon);   /* let parser know about end of stmt */
784                     force_nl = true;/* force newline after an end of stmt */
785               }
786               break;
787 
788           case lbrace:                  /* got a '{' */
789               ps.in_stmt = false;       /* dont indent the {} */
790               if (!ps.block_init)
791                     force_nl = true;/* force other stuff on same line as '{' onto
792                                          * new line */
793               else if (ps.block_init_level <= 0)
794                     ps.block_init_level = 1;
795               else
796                     ps.block_init_level++;
797 
798               if (s_code != e_code && !ps.block_init) {
799                     if (!opt.btype_2) {
800                         dump_line();
801                         ps.want_blank = false;
802                     }
803                     else if (ps.in_parameter_declaration && !ps.in_or_st) {
804                         ps.i_l_follow = 0;
805                         if (opt.function_brace_split) { /* dump the line prior
806                                          * to the brace ... */
807                               dump_line();
808                               ps.want_blank = false;
809                         } else          /* add a space between the decl and brace */
810                               ps.want_blank = true;
811                     }
812               }
813               if (ps.in_parameter_declaration)
814                     prefix_blankline_requested = 0;
815 
816               if (ps.p_l_follow > 0) {  /* check for preceding unbalanced
817                                                    * parens */
818                     diag2(1, "Unbalanced parens");
819                     ps.p_l_follow = 0;
820                     if (sp_sw) {        /* check for unclosed if, for, etc. */
821                         sp_sw = false;
822                         parse(hd_type);
823                         ps.ind_level = ps.i_l_follow;
824                     }
825               }
826               if (s_code == e_code)
827                     ps.ind_stmt = false;          /* dont put extra indentation on line
828                                                    * with '{' */
829               if (ps.in_decl && ps.in_or_st) {    /* this is either a structure
830                                                              * declaration or an init */
831                     di_stack[ps.dec_nest] = dec_ind;
832                     if (++ps.dec_nest == nitems(di_stack)) {
833                         diag3(0, "Reached internal limit of %d struct levels",
834                               nitems(di_stack));
835                         ps.dec_nest--;
836                     }
837                     /* ?                dec_ind = 0; */
838               }
839               else {
840                     ps.decl_on_line = false;      /* we can't be in the middle of
841                                                              * a declaration, so don't do
842                                                              * special indentation of
843                                                              * comments */
844                     if (opt.blanklines_after_declarations_at_proctop
845                               && ps.in_parameter_declaration)
846                         postfix_blankline_requested = 1;
847                     ps.in_parameter_declaration = 0;
848                     ps.in_decl = false;
849               }
850               dec_ind = 0;
851               parse(lbrace);  /* let parser know about this */
852               if (ps.want_blank)        /* put a blank before '{' if '{' is not at
853                                          * start of line */
854                     *e_code++ = ' ';
855               ps.want_blank = false;
856               *e_code++ = '{';
857               ps.just_saw_decl = 0;
858               break;
859 
860           case rbrace:                  /* got a '}' */
861               if (ps.p_stack[ps.tos] == decl && !ps.block_init)       /* semicolons can be
862                                                                                  * omitted in
863                                                                                  * declarations */
864                     parse(semicolon);
865               if (ps.p_l_follow) {/* check for unclosed if, for, else. */
866                     diag2(1, "Unbalanced parens");
867                     ps.p_l_follow = 0;
868                     sp_sw = false;
869               }
870               ps.just_saw_decl = 0;
871               ps.block_init_level--;
872               if (s_code != e_code && !ps.block_init) {     /* '}' must be first on
873                                                                        * line */
874                     if (opt.verbose)
875                         diag2(0, "Line broken");
876                     dump_line();
877               }
878               *e_code++ = '}';
879               ps.want_blank = true;
880               ps.in_stmt = ps.ind_stmt = false;
881               if (ps.dec_nest > 0) {    /* we are in multi-level structure
882                                                    * declaration */
883                     dec_ind = di_stack[--ps.dec_nest];
884                     if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
885                         ps.just_saw_decl = 2;
886                     ps.in_decl = true;
887               }
888               prefix_blankline_requested = 0;
889               parse(rbrace);  /* let parser know about this */
890               ps.search_brace = opt.cuddle_else && ps.p_stack[ps.tos] == ifhead
891                     && ps.il[ps.tos] >= ps.ind_level;
892               if (ps.tos <= 1 && opt.blanklines_after_procs && ps.dec_nest <= 0)
893                     postfix_blankline_requested = 1;
894               break;
895 
896           case swstmt:                  /* got keyword "switch" */
897               sp_sw = true;
898               hd_type = swstmt;         /* keep this for when we have seen the
899                                          * expression */
900               goto copy_id;   /* go move the token into buffer */
901 
902           case sp_paren:                /* token is if, while, for */
903               sp_sw = true;   /* the interesting stuff is done after the
904                                          * expression is scanned */
905               hd_type = (*token == 'i' ? ifstmt :
906                            (*token == 'w' ? whilestmt : forstmt));
907 
908               /*
909                * remember the type of header for later use by parser
910                */
911               goto copy_id;   /* copy the token into line */
912 
913           case sp_nparen:     /* got else, do */
914               ps.in_stmt = false;
915               if (*token == 'e') {
916                     if (e_code != s_code && (!opt.cuddle_else || e_code[-1] != '}')) {
917                         if (opt.verbose)
918                               diag2(0, "Line broken");
919                         dump_line();/* make sure this starts a line */
920                         ps.want_blank = false;
921                     }
922                     force_nl = true;/* also, following stuff must go onto new line */
923                     last_else = 1;
924                     parse(elselit);
925               }
926               else {
927                     if (e_code != s_code) {       /* make sure this starts a line */
928                         if (opt.verbose)
929                               diag2(0, "Line broken");
930                         dump_line();
931                         ps.want_blank = false;
932                     }
933                     force_nl = true;/* also, following stuff must go onto new line */
934                     last_else = 0;
935                     parse(dolit);
936               }
937               goto copy_id;   /* move the token into line */
938 
939           case type_def:
940           case storage:
941               prefix_blankline_requested = 0;
942               goto copy_id;
943 
944           case structure:
945               if (ps.p_l_follow > 0)
946                     goto copy_id;
947               /* FALLTHROUGH */
948           case decl:                    /* we have a declaration type (int, etc.) */
949               parse(decl);    /* let parser worry about indentation */
950               if (ps.last_token == rparen && ps.tos <= 1) {
951                     if (s_code != e_code) {
952                         dump_line();
953                         ps.want_blank = 0;
954                     }
955               }
956               if (ps.in_parameter_declaration && opt.indent_parameters && ps.dec_nest == 0) {
957                     ps.ind_level = ps.i_l_follow = 1;
958                     ps.ind_stmt = 0;
959               }
960               ps.in_or_st = true;       /* this might be a structure or initialization
961                                          * declaration */
962               ps.in_decl = ps.decl_on_line = ps.last_token != type_def;
963               if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
964                     ps.just_saw_decl = 2;
965               prefix_blankline_requested = 0;
966               for (i = 0; token[i++];); /* get length of token */
967 
968               if (ps.ind_level == 0 || ps.dec_nest > 0) {
969                     /* global variable or struct member in local variable */
970                     dec_ind = opt.decl_indent > 0 ? opt.decl_indent : i;
971                     tabs_to_var = (opt.use_tabs ? opt.decl_indent > 0 : 0);
972               } else {
973                     /* local variable */
974                     dec_ind = opt.local_decl_indent > 0 ? opt.local_decl_indent : i;
975                     tabs_to_var = (opt.use_tabs ? opt.local_decl_indent > 0 : 0);
976               }
977               goto copy_id;
978 
979           case funcname:
980           case ident:                   /* got an identifier or constant */
981               if (ps.in_decl) {
982                     if (type_code == funcname) {
983                         ps.in_decl = false;
984                         if (opt.procnames_start_line && s_code != e_code) {
985                               *e_code = '\0';
986                               dump_line();
987                         }
988                         else if (ps.want_blank) {
989                               *e_code++ = ' ';
990                         }
991                         ps.want_blank = false;
992                     }
993                     else if (!ps.block_init && !ps.dumped_decl_indent &&
994                         ps.paren_level == 0) { /* if we are in a declaration, we
995                                                       * must indent identifier */
996                         indent_declaration(dec_ind, tabs_to_var);
997                         ps.dumped_decl_indent = true;
998                         ps.want_blank = false;
999                     }
1000               }
1001               else if (sp_sw && ps.p_l_follow == 0) {
1002                     sp_sw = false;
1003                     force_nl = true;
1004                     ps.last_u_d = true;
1005                     ps.in_stmt = false;
1006                     parse(hd_type);
1007               }
1008     copy_id:
1009               {
1010                     int len = e_token - s_token;
1011 
1012                     CHECK_SIZE_CODE(len + 1);
1013                     if (ps.want_blank)
1014                         *e_code++ = ' ';
1015                     memcpy(e_code, s_token, len);
1016                     e_code += len;
1017               }
1018               if (type_code != funcname)
1019                     ps.want_blank = true;
1020               break;
1021 
1022           case strpfx:
1023               {
1024                     int len = e_token - s_token;
1025 
1026                     CHECK_SIZE_CODE(len + 1);
1027                     if (ps.want_blank)
1028                         *e_code++ = ' ';
1029                     memcpy(e_code, token, len);
1030                     e_code += len;
1031               }
1032               ps.want_blank = false;
1033               break;
1034 
1035           case period:                  /* treat a period kind of like a binary
1036                                          * operation */
1037               *e_code++ = '.';          /* move the period into line */
1038               ps.want_blank = false;    /* dont put a blank after a period */
1039               break;
1040 
1041           case comma:
1042               ps.want_blank = (s_code != e_code); /* only put blank after comma
1043                                                              * if comma does not start the
1044                                                              * line */
1045               if (ps.in_decl && ps.procname[0] == '\0' && !ps.block_init &&
1046                     !ps.dumped_decl_indent && ps.paren_level == 0) {
1047                     /* indent leading commas and not the actual identifiers */
1048                     indent_declaration(dec_ind - 1, tabs_to_var);
1049                     ps.dumped_decl_indent = true;
1050               }
1051               *e_code++ = ',';
1052               if (ps.p_l_follow == 0) {
1053                     if (ps.block_init_level <= 0)
1054                         ps.block_init = 0;
1055                     if (break_comma && (!opt.leave_comma ||
1056                         count_spaces_until(compute_code_target(), s_code, e_code) >
1057                         opt.max_col - opt.tabsize))
1058                         force_nl = true;
1059               }
1060               break;
1061 
1062           case preesc:                  /* got the character '#' */
1063               if ((s_com != e_com) ||
1064                         (s_lab != e_lab) ||
1065                         (s_code != e_code))
1066                     dump_line();
1067               CHECK_SIZE_LAB(1);
1068               *e_lab++ = '#'; /* move whole line to 'label' buffer */
1069               {
1070                     int         in_comment = 0;
1071                     int         com_start = 0;
1072                     char        quote = 0;
1073                     int         com_end = 0;
1074 
1075                     while (*buf_ptr == ' ' || *buf_ptr == '\t') {
1076                         buf_ptr++;
1077                         if (buf_ptr >= buf_end)
1078                               fill_buffer();
1079                     }
1080                     while (*buf_ptr != '\n' || (in_comment && !had_eof)) {
1081                         CHECK_SIZE_LAB(2);
1082                         *e_lab = *buf_ptr++;
1083                         if (buf_ptr >= buf_end)
1084                               fill_buffer();
1085                         switch (*e_lab++) {
1086                         case BACKSLASH:
1087                               if (!in_comment) {
1088                                   *e_lab++ = *buf_ptr++;
1089                                   if (buf_ptr >= buf_end)
1090                                         fill_buffer();
1091                               }
1092                               break;
1093                         case '/':
1094                               if (*buf_ptr == '*' && !in_comment && !quote) {
1095                                   in_comment = 1;
1096                                   *e_lab++ = *buf_ptr++;
1097                                   com_start = e_lab - s_lab - 2;
1098                               }
1099                               break;
1100                         case '"':
1101                               if (quote == '"')
1102                                   quote = 0;
1103                               break;
1104                         case '\'':
1105                               if (quote == '\'')
1106                                   quote = 0;
1107                               break;
1108                         case '*':
1109                               if (*buf_ptr == '/' && in_comment) {
1110                                   in_comment = 0;
1111                                   *e_lab++ = *buf_ptr++;
1112                                   com_end = e_lab - s_lab;
1113                               }
1114                               break;
1115                         }
1116                     }
1117 
1118                     while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1119                         e_lab--;
1120                     if (e_lab - s_lab == com_end && bp_save == NULL) {
1121                         /* comment on preprocessor line */
1122                         if (sc_end == NULL) {     /* if this is the first comment,
1123                                                              * we must set up the buffer */
1124                               save_com = sc_buf;
1125                               sc_end = &save_com[0];
1126                         }
1127                         else {
1128                               *sc_end++ = '\n';   /* add newline between
1129                                                              * comments */
1130                               *sc_end++ = ' ';
1131                               --line_no;
1132                         }
1133                         if (sc_end - save_com + com_end - com_start > sc_size)
1134                               errx(1, "input too long");
1135                         memmove(sc_end, s_lab + com_start, com_end - com_start);
1136                         sc_end += com_end - com_start;
1137                         e_lab = s_lab + com_start;
1138                         while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
1139                               e_lab--;
1140                         bp_save = buf_ptr;        /* save current input buffer */
1141                         be_save = buf_end;
1142                         buf_ptr = save_com;       /* fix so that subsequent calls to
1143                                                    * lexi will take tokens out of
1144                                                    * save_com */
1145                         *sc_end++ = ' ';          /* add trailing blank, just in case */
1146                         buf_end = sc_end;
1147                         sc_end = NULL;
1148                     }
1149                     CHECK_SIZE_LAB(1);
1150                     *e_lab = '\0';      /* null terminate line */
1151                     ps.pcase = false;
1152               }
1153 
1154               if (strncmp(s_lab, "#if", 3) == 0) { /* also ifdef, ifndef */
1155                     if ((size_t)ifdef_level < nitems(state_stack)) {
1156                         match_state[ifdef_level].tos = -1;
1157                         state_stack[ifdef_level++] = ps;
1158                     }
1159                     else
1160                         diag2(1, "#if stack overflow");
1161               }
1162               else if (strncmp(s_lab, "#el", 3) == 0) { /* else, elif */
1163                     if (ifdef_level <= 0)
1164                         diag2(1, s_lab[3] == 'i' ? "Unmatched #elif" : "Unmatched #else");
1165                     else {
1166                         match_state[ifdef_level - 1] = ps;
1167                         ps = state_stack[ifdef_level - 1];
1168                     }
1169               }
1170               else if (strncmp(s_lab, "#endif", 6) == 0) {
1171                     if (ifdef_level <= 0)
1172                         diag2(1, "Unmatched #endif");
1173                     else
1174                         ifdef_level--;
1175               } else {
1176                     struct directives {
1177                         int size;
1178                         const char *string;
1179                     }
1180                     recognized[] = {
1181                         {7, "include"},
1182                         {6, "define"},
1183                         {5, "undef"},
1184                         {4, "line"},
1185                         {5, "error"},
1186                         {6, "pragma"}
1187                     };
1188                     int d = nitems(recognized);
1189                     while (--d >= 0)
1190                         if (strncmp(s_lab + 1, recognized[d].string, recognized[d].size) == 0)
1191                               break;
1192                     if (d < 0) {
1193                         diag2(1, "Unrecognized cpp directive");
1194                         break;
1195                     }
1196               }
1197               if (opt.blanklines_around_conditional_compilation) {
1198                     postfix_blankline_requested++;
1199                     n_real_blanklines = 0;
1200               }
1201               else {
1202                     postfix_blankline_requested = 0;
1203                     prefix_blankline_requested = 0;
1204               }
1205               break;                    /* subsequent processing of the newline
1206                                          * character will cause the line to be printed */
1207 
1208           case comment:                 /* we have gotten a / followed by * this is a biggie */
1209               pr_comment();
1210               break;
1211           }                             /* end of big switch stmt */
1212 
1213           *e_code = '\0';               /* make sure code section is null terminated */
1214           if (type_code != comment && type_code != newline && type_code != preesc)
1215               ps.last_token = type_code;
1216     }                                   /* end of main while (1) loop */
1217 }
1218 
1219 /*
1220  * copy input file to backup file if in_name is /blah/blah/blah/file, then
1221  * backup file will be ".Bfile" then make the backup file the input and
1222  * original input file the output
1223  */
1224 static void
bakcopy(void)1225 bakcopy(void)
1226 {
1227     int         n,
1228                 bakchn;
1229     char        buff[8 * 1024];
1230     const char *p;
1231 
1232     /* construct file name .Bfile */
1233     for (p = in_name; *p; p++);         /* skip to end of string */
1234     while (p > in_name && *p != '/')    /* find last '/' */
1235           p--;
1236     if (*p == '/')
1237           p++;
1238     sprintf(bakfile, "%s%s", p, simple_backup_suffix);
1239 
1240     /* copy in_name to backup file */
1241     bakchn = creat(bakfile, 0600);
1242     if (bakchn < 0)
1243           err(1, "%s", bakfile);
1244     while ((n = read(fileno(input), buff, sizeof(buff))) > 0)
1245           if (write(bakchn, buff, n) != n)
1246               err(1, "%s", bakfile);
1247     if (n < 0)
1248           err(1, "%s", in_name);
1249     close(bakchn);
1250     fclose(input);
1251 
1252     /* re-open backup file as the input file */
1253     input = fopen(bakfile, "r");
1254     if (input == NULL)
1255           err(1, "%s", bakfile);
1256     /* now the original input file will be the output */
1257     output = fopen(in_name, "w");
1258     if (output == NULL) {
1259           unlink(bakfile);
1260           err(1, "%s", in_name);
1261     }
1262 }
1263 
1264 static void
indent_declaration(int cur_dec_ind,int tabs_to_var)1265 indent_declaration(int cur_dec_ind, int tabs_to_var)
1266 {
1267     int pos = e_code - s_code;
1268     char *startpos = e_code;
1269 
1270     /*
1271      * get the tab math right for indentations that are not multiples of tabsize
1272      */
1273     if ((ps.ind_level * opt.ind_size) % opt.tabsize != 0) {
1274           pos += (ps.ind_level * opt.ind_size) % opt.tabsize;
1275           cur_dec_ind += (ps.ind_level * opt.ind_size) % opt.tabsize;
1276     }
1277     if (tabs_to_var) {
1278           int tpos;
1279 
1280           CHECK_SIZE_CODE(cur_dec_ind / opt.tabsize);
1281           while ((tpos = opt.tabsize * (1 + pos / opt.tabsize)) <= cur_dec_ind) {
1282               *e_code++ = '\t';
1283               pos = tpos;
1284           }
1285     }
1286     CHECK_SIZE_CODE(cur_dec_ind - pos + 1);
1287     while (pos < cur_dec_ind) {
1288           *e_code++ = ' ';
1289           pos++;
1290     }
1291     if (e_code == startpos && ps.want_blank) {
1292           *e_code++ = ' ';
1293           ps.want_blank = false;
1294     }
1295 }
1296