56 |
#include "miscbltin.h" |
#include "miscbltin.h" |
57 |
#include "mystring.h" |
#include "mystring.h" |
58 |
#include "main.h" |
#include "main.h" |
59 |
|
#include "expand.h" |
60 |
|
#include "parser.h" |
61 |
|
|
62 |
#undef rflag |
#undef rflag |
63 |
|
|
64 |
|
|
65 |
|
/** handle one line of the read command. |
66 |
|
* more fields than variables -> remainder shall be part of last variable. |
67 |
|
* less fields than variables -> remaining variables unset. |
68 |
|
* |
69 |
|
* @param line complete line of input |
70 |
|
* @param ap argument (variable) list |
71 |
|
* @param len length of line including trailing '\0' |
72 |
|
*/ |
73 |
|
static void |
74 |
|
readcmd_handle_line(char *line, char **ap, size_t len) |
75 |
|
{ |
76 |
|
struct arglist arglist; |
77 |
|
struct strlist *sl; |
78 |
|
char *s, *backup; |
79 |
|
|
80 |
|
/* ifsbreakup will fiddle with stack region... */ |
81 |
|
s = grabstackstr(line + len); |
82 |
|
|
83 |
|
/* need a copy, so that delimiters aren't lost |
84 |
|
* in case there are more fields than variables */ |
85 |
|
backup = sstrdup(line); |
86 |
|
|
87 |
|
arglist.lastp = &arglist.list; |
88 |
|
recordregion(0, len - 1, 0); |
89 |
|
|
90 |
|
ifsbreakup(s, &arglist); |
91 |
|
*arglist.lastp = NULL; |
92 |
|
removerecordregions(0); |
93 |
|
|
94 |
|
for (sl = arglist.list; sl; sl = sl->next) { |
95 |
|
/* remaining fields present, but no variables left. */ |
96 |
|
if (!ap[1]) { |
97 |
|
size_t offset; |
98 |
|
char *remainder; |
99 |
|
|
100 |
|
/* FIXME little bit hacky, assuming that ifsbreakup |
101 |
|
* will not modify the length of the string */ |
102 |
|
offset = sl->text - s; |
103 |
|
remainder = backup + offset; |
104 |
|
rmescapes(remainder); |
105 |
|
setvar(*ap, remainder, 0); |
106 |
|
|
107 |
|
return; |
108 |
|
} |
109 |
|
|
110 |
|
/* set variable to field */ |
111 |
|
rmescapes(sl->text); |
112 |
|
setvar(*ap, sl->text, 0); |
113 |
|
ap++; |
114 |
|
} |
115 |
|
|
116 |
|
/* nullify remaining arguments */ |
117 |
|
do { |
118 |
|
setvar(*ap, nullstr, 0); |
119 |
|
} while (*++ap); |
120 |
|
} |
121 |
|
|
122 |
/* |
/* |
123 |
* The read builtin. The -e option causes backslashes to escape the |
* The read builtin. The -e option causes backslashes to escape the |
124 |
* following character. |
* following character. The -p option followed by an argument prompts |
125 |
|
* with the argument. |
126 |
* |
* |
127 |
* This uses unbuffered input, which may be avoidable in some cases. |
* This uses unbuffered input, which may be avoidable in some cases. |
128 |
*/ |
*/ |
135 |
char c; |
char c; |
136 |
int rflag; |
int rflag; |
137 |
char *prompt; |
char *prompt; |
|
const char *ifs; |
|
138 |
char *p; |
char *p; |
|
int startword; |
|
139 |
int status; |
int status; |
140 |
int timeout; |
int timeout; |
141 |
int i; |
int i; |
173 |
} |
} |
174 |
if (*(ap = argptr) == NULL) |
if (*(ap = argptr) == NULL) |
175 |
sh_error("arg count"); |
sh_error("arg count"); |
|
if ((ifs = bltinlookup("IFS")) == NULL) |
|
|
ifs = defifs; |
|
176 |
status = 0; |
status = 0; |
|
startword = 1; |
|
177 |
backslash = 0; |
backslash = 0; |
178 |
if (timeout) { |
if (timeout) { |
179 |
gettimeofday(&t0, NULL); |
gettimeofday(&t0, NULL); |
220 |
if (c == '\0') |
if (c == '\0') |
221 |
continue; |
continue; |
222 |
if (backslash) { |
if (backslash) { |
223 |
backslash = 0; |
if (c == '\n') |
224 |
if (c != '\n') |
goto resetbs; |
225 |
goto put; |
STPUTC(CTLESC, p); |
226 |
continue; |
goto put; |
227 |
} |
} |
228 |
if (!rflag && c == '\\') { |
if (!rflag && c == '\\') { |
229 |
backslash++; |
backslash++; |
231 |
} |
} |
232 |
if (c == '\n') |
if (c == '\n') |
233 |
break; |
break; |
|
if (startword && *ifs == ' ' && strchr(ifs, c)) { |
|
|
continue; |
|
|
} |
|
|
startword = 0; |
|
|
if (ap[1] != NULL && strchr(ifs, c) != NULL) { |
|
|
STACKSTRNUL(p); |
|
|
setvar(*ap, stackblock(), 0); |
|
|
ap++; |
|
|
startword = 1; |
|
|
STARTSTACKSTR(p); |
|
|
} else { |
|
234 |
put: |
put: |
235 |
STPUTC(c, p); |
STPUTC(c, p); |
236 |
} |
resetbs: |
237 |
|
backslash = 0; |
238 |
} |
} |
239 |
STACKSTRNUL(p); |
STACKSTRNUL(p); |
240 |
/* Remove trailing blanks */ |
readcmd_handle_line(stackblock(), ap, p + 1 - (char *)stackblock()); |
|
while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL) |
|
|
*p = '\0'; |
|
|
setvar(*ap, stackblock(), 0); |
|
|
while (*++ap != NULL) |
|
|
setvar(*ap, nullstr, 0); |
|
241 |
return status; |
return status; |
242 |
} |
} |
243 |
|
|
292 |
} else { |
} else { |
293 |
int new_mask; |
int new_mask; |
294 |
|
|
295 |
if (isdigit(*ap)) { |
if (isdigit((unsigned char) *ap)) { |
296 |
new_mask = 0; |
new_mask = 0; |
297 |
do { |
do { |
298 |
if (*ap >= '8' || *ap < '0') |
if (*ap >= '8' || *ap < '0') |