1 /* $OpenBSD: lex.c,v 1.47 2013/03/03 19:11:34 guenther Exp $ */
4 * lexical analysis and source input
12 /* Structure to keep track of the lexing state and the various pieces of info
13 * needed for each particular state.
15 typedef struct lex_state Lex_state
;
20 struct scsparen_info
{
21 int nparen
; /* count open parenthesis */
22 int csstate
; /* XXX remove */
23 #define ls_scsparen ls_info.u_scsparen
27 struct sasparen_info
{
28 int nparen
; /* count open parenthesis */
29 int start
; /* marks start of $(( in output str */
30 #define ls_sasparen ls_info.u_sasparen
34 struct sletparen_info
{
35 int nparen
; /* count open parenthesis */
36 #define ls_sletparen ls_info.u_sletparen
41 int indquotes
; /* true if in double quotes: "`...`" */
42 #define ls_sbquote ls_info.u_sbquote
45 Lex_state
*base
; /* used to point to next state block */
49 typedef struct State_info State_info
;
56 static void readhere(struct ioword
*);
57 static int getsc__(void);
58 static void getsc_line(Source
*);
59 static int getsc_bn(void);
60 static char *get_brace_var(XString
*, char *);
61 static int arraysub(char **);
62 static const char *ungetsc(int);
63 static void gethere(void);
64 static Lex_state
*push_state_(State_info
*, Lex_state
*);
65 static Lex_state
*pop_state_(State_info
*, Lex_state
*);
66 static char *special_prompt_expand(char *);
67 static int dopprompt(const char *, int, const char **, int);
69 static int backslash_skip
;
70 static int ignore_backslash_newline
;
72 /* optimized getsc_bn() */
73 #define getsc() (*source->str != '\0' && *source->str != '\\' \
74 && !backslash_skip ? *source->str++ : getsc_bn())
75 /* optimized getsc__() */
76 #define getsc_() ((*source->str != '\0') ? *source->str++ : getsc__())
78 #define STATE_BSIZE 32
80 #define PUSH_STATE(s) do { \
81 if (++statep == state_info.end) \
82 statep = push_state_(&state_info, statep); \
83 state = statep->ls_state = (s); \
86 #define POP_STATE() do { \
87 if (--statep == state_info.base) \
88 statep = pop_state_(&state_info, statep); \
89 state = statep->ls_state; \
97 * tokens are not regular expressions, they are LL(1).
98 * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
99 * hence the state stack.
105 Lex_state states
[STATE_BSIZE
], *statep
;
106 State_info state_info
;
108 XString ws
; /* expandable output word */
109 char *wp
; /* output word pointer */
115 states
[0].ls_state
= -1;
116 states
[0].ls_info
.base
= NULL
;
118 state_info
.base
= states
;
119 state_info
.end
= &states
[STATE_BSIZE
];
121 Xinit(ws
, wp
, 64, ATEMP
);
124 ignore_backslash_newline
= 0;
128 else if (cf
&LETEXPR
) {
129 *wp
++ = OQUOTE
; /* enclose arguments in (double) quotes */
131 statep
->ls_sletparen
.nparen
= 0;
132 } else { /* normal lexing */
133 state
= (cf
& HEREDELIM
) ? SHEREDELIM
: SBASE
;
134 while ((c
= getsc()) == ' ' || c
== '\t')
137 ignore_backslash_newline
++;
138 while ((c
= getsc()) != '\0' && c
!= '\n')
140 ignore_backslash_newline
--;
144 if (source
->flags
& SF_ALIAS
) { /* trailing ' ' in alias definition */
145 source
->flags
&= ~SF_ALIAS
;
146 /* In POSIX mode, a trailing space only counts if we are
147 * parsing a simple command
149 if (!Flag(FPOSIX
) || (cf
& CMDWORD
))
153 /* Initial state: one of SBASE SHEREDELIM SWORD SASPAREN */
154 statep
->ls_state
= state
;
156 /* collect non-special or quoted characters to form word */
157 while (!((c
= getsc()) == 0 ||
158 ((state
== SBASE
|| state
== SHEREDELIM
) && ctype(c
, C_LEX1
)))) {
162 if (Flag(FCSHHISTORY
) && (source
->flags
& SF_TTY
) &&
164 char **replace
= NULL
;
167 if (c2
== '\0' || c2
== ' ' || c2
== '\t')
170 replace
= hist_get_newest(0);
171 else if (isdigit(c2
) || c2
== '-' ||
173 int get
= !isalpha(c2
);
174 char match
[200], *str
= match
;
178 if ((c2
= getsc()) == '\0')
180 if (c2
== '\t' || c2
== ' ' ||
186 } while (str
< &match
[sizeof(match
)-1]);
190 int h
= findhistrel(match
);
192 replace
= &history
[h
];
194 int h
= findhist(-1, 0, match
, true);
196 replace
= &history
[h
];
201 * XXX ksh history buffer saves un-expanded
202 * commands. Until the history buffer code is
203 * changed to contain expanded commands, we
204 * ignore the bad commands (spinning sucks)
206 if (replace
&& **replace
== '!')
211 /* do not strdup replacement via alloc */
212 s
= pushs(SREREAD
, source
->areap
);
213 s
->start
= s
->str
= *replace
;
221 if (c
== '[' && (cf
& (VARASN
|ARRAYVAR
))) {
222 *wp
= EOS
; /* temporary */
223 if (is_wdvarname(Xstring(ws
, wp
), false)) {
226 if (arraysub(&tmp
)) {
229 for (p
= tmp
; *p
; ) {
252 Sbase1
: /* includes *(...|...) pattern (*+?@!) */
253 if (c
== '*' || c
== '@' || c
== '+' || c
== '?' ||
256 if (c2
== '(' /*)*/ ) {
259 PUSH_STATE(SPATTERN
);
265 Sbase2
: /* doesn't include *(...|...) pattern (*+?@!) */
269 if (c
) /* trailing \ is lost */
270 *wp
++ = QCHAR
, *wp
++ = c
;
273 if ((cf
& HEREDOC
) || state
== SBRACEQ
) {
274 *wp
++ = CHAR
, *wp
++ = c
;
278 ignore_backslash_newline
++;
297 *wp
++ = QCHAR
, *wp
++ = c
;
300 if ((cf
& HEREDOC
) == 0) {
301 *wp
++ = QCHAR
, *wp
++ = c
;
307 *wp
++ = QCHAR
, *wp
++ = c
;
311 if (c
) { /* trailing \ is lost */
312 *wp
++ = CHAR
, *wp
++ = '\\';
313 *wp
++ = CHAR
, *wp
++ = c
;
320 if (c
== '(') /*)*/ {
322 if (c
== '(') /*)*/ {
323 PUSH_STATE(SASPAREN
);
324 statep
->ls_sasparen
.nparen
= 2;
325 statep
->ls_sasparen
.start
=
330 PUSH_STATE(SCSPAREN
);
331 statep
->ls_scsparen
.nparen
= 1;
332 statep
->ls_scsparen
.csstate
= 0;
335 } else if (c
== '{') /*}*/ {
338 wp
= get_brace_var(&ws
, wp
);
340 /* allow :# and :% (ksh88 compat) */
342 *wp
++ = CHAR
, *wp
++ = c
;
345 /* If this is a trim operation,
346 * treat (,|,) specially in STBRACE.
348 if (c
== '#' || c
== '%') {
353 if (state
== SDQUOTE
||
359 } else if (ctype(c
, C_ALPHA
)) {
366 } while (ctype(c
, C_ALPHA
|C_DIGIT
));
371 } else if (ctype(c
, C_DIGIT
|C_VAR1
)) {
380 *wp
++ = CHAR
, *wp
++ = '$';
387 /* Need to know if we are inside double quotes
388 * since sh/at&t-ksh translate the \" to " in
390 * This is not done in posix mode (section
391 * 3.2.3, Double Quotes: "The backquote shall
392 * retain its special meaning introducing the
393 * other form of command substitution (see
394 * 3.6.3). The portion of the quoted string
395 * from the initial backquote and the
396 * characters up to the next backquote that
397 * is not preceded by a backslash (having
398 * escape characters removed) defines that
399 * command whose output replaces `...` when
400 * the word is expanded."
401 * Section 3.6.3, Command Substitution:
402 * "Within the backquoted style of command
403 * substitution, backslash shall retain its
404 * literal meaning, except when followed by
407 statep
->ls_sbquote
.indquotes
= 0;
409 Lex_state
*s
= statep
;
410 Lex_state
*base
= state_info
.base
;
412 for (; s
!= base
; s
--) {
413 if (s
->ls_state
== SDQUOTE
) {
414 statep
->ls_sbquote
.indquotes
= 1;
420 if (!(s
= s
->ls_info
.base
))
422 base
= s
-- - STATE_BSIZE
;
427 *wp
++ = CHAR
, *wp
++ = c
;
434 if (state
== SBRACEQ
) {
435 *wp
++ = CHAR
, *wp
++ = c
;
439 ignore_backslash_newline
--;
441 *wp
++ = QCHAR
, *wp
++ = c
;
452 case SCSPAREN
: /* $( .. ) */
453 /* todo: deal with $(...) quoting properly
454 * kludge to partly fake quoting inside $(..): doesn't
455 * really work because nested $(..) or ${..} inside
456 * double quotes aren't dealt with.
458 switch (statep
->ls_scsparen
.csstate
) {
462 statep
->ls_scsparen
.nparen
++;
465 statep
->ls_scsparen
.nparen
--;
468 statep
->ls_scsparen
.csstate
= 1;
471 statep
->ls_scsparen
.csstate
= 2;
474 statep
->ls_scsparen
.csstate
= 4;
475 ignore_backslash_newline
++;
480 case 1: /* backslash in normal mode */
481 case 3: /* backslash in double quotes */
482 --statep
->ls_scsparen
.csstate
;
485 case 2: /* double quotes */
487 statep
->ls_scsparen
.csstate
= 0;
489 statep
->ls_scsparen
.csstate
= 3;
492 case 4: /* single quotes */
494 statep
->ls_scsparen
.csstate
= 0;
495 ignore_backslash_newline
--;
499 if (statep
->ls_scsparen
.nparen
== 0) {
501 *wp
++ = 0; /* end of COMSUB */
506 case SASPAREN
: /* $(( .. )) */
507 /* todo: deal with $((...); (...)) properly */
508 /* XXX should nest using existing state machine
509 * (embed "..", $(...), etc.) */
511 statep
->ls_sasparen
.nparen
++;
513 statep
->ls_sasparen
.nparen
--;
514 if (statep
->ls_sasparen
.nparen
== 1) {
516 if ((c2
= getsc()) == ')') {
518 *wp
++ = 0; /* end of EXPRSUB */
524 /* mismatched parenthesis -
525 * assume we were really
526 * parsing a $(..) expression
529 statep
->ls_sasparen
.start
);
530 memmove(s
+ 1, s
, wp
- s
);
534 statep
->ls_scsparen
.nparen
= 1;
535 statep
->ls_scsparen
.csstate
= 0;
536 state
= statep
->ls_state
=
556 /* Same as SBRACE, except (,|,) treated specially */
562 } else if (c
== '|') {
564 } else if (c
== '(') {
566 *wp
++ = ' '; /* simile for @ */
567 PUSH_STATE(SPATTERN
);
576 } else if (c
== '\\') {
577 switch (c
= getsc()) {
583 if (statep
->ls_sbquote
.indquotes
) {
589 if (c
) { /* trailing \ is lost */
599 case SWORD
: /* ONEWORD */
602 case SLETPAREN
: /* LETEXPR: (( ... )) */
605 if (statep
->ls_sletparen
.nparen
> 0)
606 --statep
->ls_sletparen
.nparen
;
608 else if ((c2
= getsc()) == ')') {
615 /* parenthesis inside quotes and backslashes
616 * are lost, but at&t ksh doesn't count them
619 ++statep
->ls_sletparen
.nparen
;
622 case SHEREDELIM
: /* <<,<<- delimiter */
623 /* XXX chuck this state (and the next) - use
624 * the existing states ($ and \`..` should be
625 * stripped of their specialness after the
628 /* here delimiters need a special case since
629 * $ and `..` are not to be treated specially
633 if (c
) { /* trailing \ is lost */
637 } else if (c
== '\'') {
640 ignore_backslash_newline
++;
641 } else if (c
== '"') {
642 state
= statep
->ls_state
= SHEREDQUOTE
;
650 case SHEREDQUOTE
: /* " in <<,<<- delimiter */
653 state
= statep
->ls_state
= SHEREDELIM
;
656 switch (c
= getsc()) {
661 if (c
) { /* trailing \ lost */
673 case SPATTERN
: /* in *(...|...) pattern (*+?@!) */
674 if ( /*(*/ c
== ')') {
677 } else if (c
== '|') {
679 } else if (c
== '(') {
681 *wp
++ = ' '; /* simile for @ */
682 PUSH_STATE(SPATTERN
);
690 if (statep
!= &states
[1])
691 /* XXX figure out what is missing */
692 yyerror("no closing quote\n");
694 /* This done to avoid tests for SHEREDELIM wherever SBASE tested */
695 if (state
== SHEREDELIM
)
698 dp
= Xstring(ws
, wp
);
699 if ((c
== '<' || c
== '>') && state
== SBASE
&&
700 ((c2
= Xlength(ws
, wp
)) == 0 ||
701 (c2
== 2 && dp
[0] == CHAR
&& digit(dp
[1])))) {
702 struct ioword
*iop
= (struct ioword
*) alloc(sizeof(*iop
), ATEMP
);
705 iop
->unit
= dp
[1] - '0';
707 iop
->unit
= c
== '>'; /* 0 for <, 1 for > */
710 /* <<, >>, <> are ok, >< is not */
711 if (c
== c2
|| (c
== '<' && c2
== '>')) {
712 iop
->flag
= c
== c2
?
713 (c
== '>' ? IOCAT
: IOHERE
) : IORDWR
;
714 if (iop
->flag
== IOHERE
) {
715 if ((c2
= getsc()) == '-')
720 } else if (c2
== '&')
721 iop
->flag
= IODUP
| (c
== '<' ? IORDUP
: 0);
723 iop
->flag
= c
== '>' ? IOWRITE
: IOREAD
;
724 if (c
== '>' && c2
== '|')
730 iop
->name
= (char *) 0;
731 iop
->delim
= (char *) 0;
732 iop
->heredoc
= (char *) 0;
733 Xfree(ws
, wp
); /* free word */
738 if (wp
== dp
&& state
== SBASE
) {
739 Xfree(ws
, wp
); /* free word */
740 /* no word, process LEX1 character */
748 if ((c2
= getsc()) == c
)
749 c
= (c
== ';') ? BREAK
:
751 (c
== '&') ? LOGAND
:
753 else if (c
== '|' && c2
== '&')
767 if ((c2
= getsc()) == '(') /*)*/
768 /* XXX need to handle ((...); (...)) */
780 *wp
++ = EOS
; /* terminate word */
781 yylval
.cp
= Xclose(ws
, wp
);
782 if (state
== SWORD
|| state
== SLETPAREN
) /* ONEWORD? */
784 ungetsc(c
); /* unget terminator */
786 /* copy word to unprefixed string ident */
787 for (sp
= yylval
.cp
, dp
= ident
; dp
< ident
+IDENT
&& (c
= *sp
++) == CHAR
; )
789 /* Make sure the ident array stays '\0' padded */
790 memset(dp
, 0, (ident
+IDENT
) - dp
+ 1);
792 *ident
= '\0'; /* word is not unquoted */
794 if (*ident
!= '\0' && (cf
&(KEYWORD
|ALIAS
))) {
799 if ((cf
& KEYWORD
) && (p
= ktsearch(&keywords
, ident
, h
)) &&
800 (!(cf
& ESACONLY
) || p
->val
.i
== ESAC
|| p
->val
.i
== '}')) {
801 afree(yylval
.cp
, ATEMP
);
804 if ((cf
& ALIAS
) && (p
= ktsearch(&aliases
, ident
, h
)) &&
808 for (s
= source
; s
->type
== SALIAS
; s
= s
->next
)
811 /* push alias expansion */
812 s
= pushs(SALIAS
, source
->areap
);
813 s
->start
= s
->str
= p
->val
.s
;
817 afree(yylval
.cp
, ATEMP
);
830 for (p
= heres
; p
< herep
; p
++)
836 * read "<<word" text into temp file
840 readhere(struct ioword
*iop
)
850 eof
= evalstr(iop
->delim
, 0);
852 if (!(iop
->flag
& IOEVAL
))
853 ignore_backslash_newline
++;
855 Xinit(xs
, xp
, 256, ATEMP
);
859 skiptabs
= iop
->flag
& IOSKIP
;
860 xpos
= Xsavepos(xs
, xp
);
861 while ((c
= getsc()) != 0) {
873 /* Allow EOF here so commands with out trailing newlines
874 * will work (eg, ksh -c '...', $(...), etc).
876 if (*eofp
== '\0' && (c
== 0 || c
== '\n')) {
877 xp
= Xrestpos(xs
, xp
, xpos
);
881 while ((c
= getsc()) != '\n') {
883 yyerror("here document `%s' unclosed\n", eof
);
891 iop
->heredoc
= Xclose(xs
, xp
);
893 if (!(iop
->flag
& IOEVAL
))
894 ignore_backslash_newline
--;
898 yyerror(const char *fmt
, ...)
902 /* pop aliases and re-reads */
903 while (source
->type
== SALIAS
|| source
->type
== SREREAD
)
904 source
= source
->next
;
905 source
->str
= null
; /* zap pending input */
909 shf_vfprintf(shl_out
, fmt
, va
);
915 * input for yylex with alias expansion
919 pushs(int type
, Area
*areap
)
923 s
= (Source
*) alloc(sizeof(Source
), areap
);
934 if (type
== SFILE
|| type
== SSTDIN
) {
936 Xinit(s
->xs
, dummy
, 256, s
->areap
);
938 memset(&s
->xs
, 0, sizeof(s
->xs
));
948 while ((c
= *s
->str
++) == 0) {
949 s
->str
= NULL
; /* return 0 for EOF by default */
967 s
->start
= s
->str
= *s
->u
.strv
++;
972 if (*s
->u
.strv
== NULL
) {
973 s
->start
= s
->str
= newline
;
976 s
->start
= s
->str
= space
;
982 if (s
->flags
& SF_ALIASEND
) {
983 /* pass on an unused SF_ALIAS flag */
985 source
->flags
|= s
->flags
& SF_ALIAS
;
987 } else if (*s
->u
.tblp
->val
.s
&&
988 isspace(strchr(s
->u
.tblp
->val
.s
, 0)[-1])) {
989 source
= s
= s
->next
; /* pop source stack */
990 /* Note that this alias ended with a space,
991 * enabling alias expansion on the following
994 s
->flags
|= SF_ALIAS
;
996 /* At this point, we need to keep the current
997 * alias in the source list so recursive
998 * aliases can be detected and we also need
999 * to return the next character. Do this
1000 * by temporarily popping the alias to get
1001 * the next character and then put it back
1002 * in the source list with the SF_ALIASEND
1005 source
= s
->next
; /* pop source stack */
1006 source
->flags
|= s
->flags
& SF_ALIAS
;
1009 s
->flags
|= SF_ALIASEND
;
1010 s
->ugbuf
[0] = c
; s
->ugbuf
[1] = '\0';
1011 s
->start
= s
->str
= s
->ugbuf
;
1016 /* avoid reading eof twice */
1024 if (s
->start
!= s
->ugbuf
) /* yuck */
1025 afree(s
->u
.freeme
, ATEMP
);
1026 source
= s
= s
->next
;
1029 if (s
->str
== NULL
) {
1031 s
->start
= s
->str
= null
;
1034 if (s
->flags
& SF_ECHO
) {
1035 shf_puts(s
->str
, shl_out
);
1043 getsc_line(Source
*s
)
1045 char *xp
= Xstring(s
->xs
, xp
);
1046 int interactive
= Flag(FTALKING
) && s
->type
== SSTDIN
;
1047 int have_tty
= interactive
&& (s
->flags
& SF_TTY
);
1049 /* Done here to ensure nothing odd happens when a timeout occurs */
1050 XcheckN(s
->xs
, xp
, LINE
);
1052 s
->start
= s
->str
= xp
;
1054 if (have_tty
&& ksh_tmout
) {
1055 ksh_tmout_state
= TMOUT_READING
;
1064 || Flag(FEMACS
) || Flag(FGMACS
)
1069 nread
= x_read(xp
, LINE
);
1070 if (nread
< 0) /* read error */
1084 char *p
= shf_getse(xp
, Xnleft(s
->xs
, xp
), s
->u
.shf
);
1086 if (!p
&& shf_error(s
->u
.shf
) &&
1087 shf_errno(s
->u
.shf
) == EINTR
) {
1088 shf_clearerr(s
->u
.shf
);
1093 if (!p
|| (xp
= p
, xp
[-1] == '\n'))
1095 /* double buffer size */
1096 xp
++; /* move past null so doubling works... */
1097 XcheckN(s
->xs
, xp
, Xlength(s
->xs
, xp
));
1098 xp
--; /* ...and move back again */
1100 /* flush any unwanted input so other programs/builtins
1101 * can read it. Not very optimal, but less error prone
1102 * than flushing else where, dealing with redirections,
1104 * todo: reduce size of shf buffer (~128?) if SSTDIN
1106 if (s
->type
== SSTDIN
)
1107 shf_flush(s
->u
.shf
);
1109 /* XXX: temporary kludge to restore source after a
1110 * trap may have been executed.
1113 if (have_tty
&& ksh_tmout
) {
1114 ksh_tmout_state
= TMOUT_EXECUTING
;
1117 s
->start
= s
->str
= Xstring(s
->xs
, xp
);
1118 strip_nuls(Xstring(s
->xs
, xp
), Xlength(s
->xs
, xp
));
1119 /* Note: if input is all nulls, this is not eof */
1120 if (Xlength(s
->xs
, xp
) == 0) { /* EOF */
1121 if (s
->type
== SFILE
)
1122 shf_fdclose(s
->u
.shf
);
1124 } else if (interactive
) {
1126 char *p
= Xstring(s
->xs
, xp
);
1127 if (cur_prompt
== PS1
)
1128 while (*p
&& ctype(*p
, C_IFS
) && ctype(*p
, C_IFSWS
))
1132 histsave(s
->line
, s
->str
, 1);
1134 #endif /* HISTORY */
1137 set_prompt(PS2
, (Source
*) 0);
1141 special_prompt_expand(char *str
)
1145 while ((p
= strstr(p
, "\\$")) != NULL
) {
1152 set_prompt(int to
, Source
*s
)
1160 case PS1
: /* command */
1161 ps1
= str_save(str_val(global("PS1")), ATEMP
);
1162 saved_atemp
= ATEMP
; /* ps1 is freed by substitute() */
1164 if (sigsetjmp(e
->jbuf
, 0)) {
1165 prompt
= safe_prompt
;
1166 /* Don't print an error - assume it has already
1167 * been printed. Reason is we may have forked
1168 * to run a command and the child may be
1169 * unwinding its stack through this code as it
1173 /* expand \$ before other substitutions are done */
1174 char *tmp
= special_prompt_expand(ps1
);
1175 prompt
= str_save(substitute(tmp
, 0), saved_atemp
);
1179 case PS2
: /* command continuation */
1180 prompt
= str_val(global("PS2"));
1186 dopprompt(const char *sp
, int ntruncate
, const char **spp
, int doprint
)
1188 char strbuf
[1024], tmpbuf
[1024], *p
, *str
, nbuf
[32], delimiter
= '\0';
1189 int len
, c
, n
, totlen
= 0, indelimit
= 0, counting
= 1, delimitthis
;
1190 const char *cp
= sp
;
1194 if (*cp
&& cp
[1] == '\r') {
1201 if (indelimit
&& *cp
!= delimiter
)
1203 else if (*cp
== '\n' || *cp
== '\r') {
1206 } else if (*cp
== '\t') {
1208 totlen
= (totlen
| 7) + 1;
1209 } else if (*cp
== delimiter
) {
1210 indelimit
= !indelimit
;
1219 snprintf(strbuf
, sizeof strbuf
, "\\%c", *cp
);
1221 case 'a': /* '\' 'a' bell */
1225 case 'd': /* '\' 'd' Dow Mon DD */
1228 strftime(strbuf
, sizeof strbuf
, "%a %b %d", tm
);
1230 case 'D': /* '\' 'D' '{' strftime format '}' */
1231 p
= strchr(cp
+ 2, '}');
1232 if (cp
[1] != '{' || p
== NULL
) {
1233 snprintf(strbuf
, sizeof strbuf
,
1237 strlcpy(tmpbuf
, cp
+ 2, sizeof tmpbuf
);
1238 p
= strchr(tmpbuf
, '}');
1243 strftime(strbuf
, sizeof strbuf
, tmpbuf
, tm
);
1244 cp
= strchr(cp
+ 2, '}');
1246 case 'e': /* '\' 'e' escape */
1250 case 'h': /* '\' 'h' shortened hostname */
1251 gethostname(strbuf
, sizeof strbuf
);
1252 p
= strchr(strbuf
, '.');
1256 case 'H': /* '\' 'H' full hostname */
1257 gethostname(strbuf
, sizeof strbuf
);
1259 case 'j': /* '\' 'j' number of jobs */
1260 snprintf(strbuf
, sizeof strbuf
, "%d",
1263 case 'l': /* '\' 'l' basename of tty */
1268 strlcpy(strbuf
, p
, sizeof strbuf
);
1270 case 'n': /* '\' 'n' newline */
1273 totlen
= 0; /* reset for prompt re-print */
1276 case 'p': /* '\' '$' $ or # */
1277 strbuf
[0] = ksheuid
? '$' : '#';
1280 case 'r': /* '\' 'r' return */
1283 totlen
= 0; /* reset for prompt re-print */
1286 case 's': /* '\' 's' basename $0 */
1287 strlcpy(strbuf
, kshname
, sizeof strbuf
);
1289 case 't': /* '\' 't' 24 hour HH:MM:SS */
1292 strftime(strbuf
, sizeof strbuf
, "%T", tm
);
1294 case 'T': /* '\' 'T' 12 hour HH:MM:SS */
1297 strftime(strbuf
, sizeof strbuf
, "%l:%M:%S", tm
);
1299 case '@': /* '\' '@' 12 hour am/pm format */
1302 strftime(strbuf
, sizeof strbuf
, "%r", tm
);
1304 case 'A': /* '\' 'A' 24 hour HH:MM */
1307 strftime(strbuf
, sizeof strbuf
, "%R", tm
);
1309 case 'u': /* '\' 'u' username */
1310 strlcpy(strbuf
, username
, sizeof strbuf
);
1312 case 'v': /* '\' 'v' version (short) */
1313 p
= strchr(ksh_version
, ' ');
1315 p
= strchr(p
+ 1, ' ');
1318 strlcpy(strbuf
, p
, sizeof strbuf
);
1319 p
= strchr(strbuf
, ' ');
1324 case 'V': /* '\' 'V' version (long) */
1325 strlcpy(strbuf
, ksh_version
, sizeof strbuf
);
1327 case 'w': /* '\' 'w' cwd */
1328 p
= str_val(global("PWD"));
1329 n
= strlen(str_val(global("HOME")));
1330 if (strcmp(p
, "/") == 0) {
1331 strlcpy(strbuf
, p
, sizeof strbuf
);
1332 } else if (strcmp(p
, str_val(global("HOME"))) == 0) {
1335 } else if (strncmp(p
, str_val(global("HOME")), n
)
1336 == 0 && p
[n
] == '/') {
1337 snprintf(strbuf
, sizeof strbuf
, "~/%s",
1338 str_val(global("PWD")) + n
+ 1);
1340 strlcpy(strbuf
, p
, sizeof strbuf
);
1342 case 'W': /* '\' 'W' basename(cwd) */
1343 p
= str_val(global("PWD"));
1344 if (strcmp(p
, str_val(global("HOME"))) == 0) {
1348 strlcpy(strbuf
, basename(p
), sizeof strbuf
);
1350 case '!': /* '\' '!' history line number */
1351 snprintf(strbuf
, sizeof strbuf
, "%d",
1354 case '#': /* '\' '#' command line number */
1355 snprintf(strbuf
, sizeof strbuf
, "%d",
1356 source
->line
- source
->cmd_offset
+ 1);
1358 case '0': /* '\' '#' '#' ' #' octal numeric handling */
1366 if ((cp
[1] > '7' || cp
[1] < '0') ||
1367 (cp
[2] > '7' || cp
[2] < '0')) {
1368 snprintf(strbuf
, sizeof strbuf
,
1372 n
= cp
[0] * 8 * 8 + cp
[1] * 8 + cp
[2];
1373 snprintf(strbuf
, sizeof strbuf
, "%c", n
);
1376 case '\\': /* '\' '\' */
1380 case '[': /* '\' '[' .... stop counting */
1384 case ']': /* '\' ']' restart counting */
1390 snprintf(strbuf
, sizeof strbuf
, "\\%c", *cp
);
1398 if (ntruncate
>= len
) {
1407 shf_write(str
, len
, shl_out
);
1408 if (counting
&& !indelimit
&& !delimitthis
)
1411 } else if (*cp
!= '!')
1413 else if (*++cp
== '!')
1418 shf_snprintf(p
= nbuf
, sizeof(nbuf
), "%d",
1422 if (ntruncate
>= len
) {
1431 shf_write(p
, len
, shl_out
);
1432 if (counting
&& !indelimit
&& !delimitthis
)
1436 if (counting
&& ntruncate
)
1439 shf_putc(c
, shl_out
);
1441 if (counting
&& !indelimit
&& !delimitthis
)
1452 pprompt(const char *cp
, int ntruncate
)
1454 dopprompt(cp
, ntruncate
, NULL
, 1);
1458 promptlen(const char *cp
, const char **spp
)
1460 return dopprompt(cp
, 0, spp
, 0);
1463 /* Read the variable part of a ${...} expression (ie, up to but not including
1464 * the :[-+?=#%] or close-brace.
1467 get_brace_var(XString
*wsp
, char *wp
)
1470 PS_INITIAL
, PS_SAW_HASH
, PS_IDENT
,
1471 PS_NUMBER
, PS_VAR1
, PS_END
1479 /* State machine to figure out where the variable part ends. */
1483 state
= PS_SAW_HASH
;
1492 else if (ctype(c
, C_VAR1
))
1503 if (!arraysub(&tmp
))
1504 yyerror("missing ]\n");
1506 for (p
= tmp
; *p
; ) {
1511 c
= getsc(); /* the ] */
1522 case PS_END
: /* keep gcc happy */
1525 if (state
== PS_END
) {
1526 *wp
++ = '\0'; /* end of variable part */
1537 * Save an array subscript - returns true if matching bracket found, false
1538 * if eof or newline was found.
1539 * (Returned string double null terminated)
1542 arraysub(char **strp
)
1547 int depth
= 1; /* we are just past the initial [ */
1549 Xinit(ws
, wp
, 32, ATEMP
);
1559 } while (depth
> 0 && c
&& c
!= '\n');
1562 *strp
= Xclose(ws
, wp
);
1564 return depth
== 0 ? 1 : 0;
1567 /* Unget a char: handles case when we are already at the start of the buffer */
1573 /* Don't unget eof... */
1574 if (source
->str
== null
&& c
== '\0')
1576 if (source
->str
> source
->start
)
1581 s
= pushs(SREREAD
, source
->areap
);
1582 s
->ugbuf
[0] = c
; s
->ugbuf
[1] = '\0';
1583 s
->start
= s
->str
= s
->ugbuf
;
1591 /* Called to get a char that isn't a \newline sequence. */
1597 if (ignore_backslash_newline
)
1600 if (backslash_skip
== 1) {
1610 if ((c2
= getsc_()) == '\n')
1611 /* ignore the \newline; get the next char... */
1621 push_state_(State_info
*si
, Lex_state
*old_end
)
1623 Lex_state
*new = alloc(sizeof(Lex_state
) * STATE_BSIZE
, ATEMP
);
1625 new[0].ls_info
.base
= old_end
;
1627 si
->end
= &new[STATE_BSIZE
];
1632 pop_state_(State_info
*si
, Lex_state
*old_end
)
1634 Lex_state
*old_base
= si
->base
;
1636 si
->base
= old_end
->ls_info
.base
- STATE_BSIZE
;
1637 si
->end
= old_end
->ls_info
.base
;
1639 afree(old_base
, ATEMP
);
1641 return si
->base
+ STATE_BSIZE
- 1;