Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / cmd / ksh93 / bltins / read.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: read.c /main/3 1995/11/01 16:29:22 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *        THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF        *
29 *                    AT&T BELL LABORATORIES                    *
30 *         AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN         *
31 *            ACCORDANCE WITH APPLICABLE AGREEMENTS             *
32 *                                                              *
33 *                Copyright (c) 1995 AT&T Corp.                 *
34 *              Unpublished & Not for Publication               *
35 *                     All Rights Reserved                      *
36 *                                                              *
37 *       The copyright notice above does not evidence any       *
38 *      actual or intended publication of such source code      *
39 *                                                              *
40 *               This software was created by the               *
41 *           Advanced Software Technology Department            *
42 *                    AT&T Bell Laboratories                    *
43 *                                                              *
44 *               For further information contact                *
45 *                    {research,attmail}!dgk                    *
46 *                                                              *
47 ***************************************************************/
48
49 /* : : generated by proto : : */
50
51 #if !defined(__PROTO__)
52 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
53 #if defined(__cplusplus)
54 #define __MANGLE__      "C"
55 #else
56 #define __MANGLE__
57 #endif
58 #define __STDARG__
59 #define __PROTO__(x)    x
60 #define __OTORP__(x)
61 #define __PARAM__(n,o)  n
62 #if !defined(__STDC__) && !defined(__cplusplus)
63 #if !defined(c_plusplus)
64 #define const
65 #endif
66 #define signed
67 #define void            int
68 #define volatile
69 #define __V_            char
70 #else
71 #define __V_            void
72 #endif
73 #else
74 #define __PROTO__(x)    ()
75 #define __OTORP__(x)    x
76 #define __PARAM__(n,o)  o
77 #define __MANGLE__
78 #define __V_            char
79 #define const
80 #define signed
81 #define void            int
82 #define volatile
83 #endif
84 #if defined(__cplusplus) || defined(c_plusplus)
85 #define __VARARG__      ...
86 #else
87 #define __VARARG__
88 #endif
89 #if defined(__STDARG__)
90 #define __VA_START__(p,a)       va_start(p,a)
91 #else
92 #define __VA_START__(p,a)       va_start(p)
93 #endif
94 #endif
95 #include        <ast.h>
96 #include        <error.h>
97 #include        <ctype.h>
98 #include        "defs.h"
99 #include        "variables.h"
100 #include        "lexstates.h"
101 #include        "io.h"
102 #include        "name.h"
103 #include        "builtins.h"
104 #include        "history.h"
105 #include        "terminal.h"
106 #include        "national.h"
107
108 #define R_FLAG  1       /* raw mode */
109 #define S_FLAG  2       /* save in history file */
110 #define A_FLAG  4       /* read into array */
111 #define D_FLAG  6       /* must be number of bits for all flags */
112
113 int     b_read __PARAM__((int argc,char *argv[], __V_ *extra), (argc, argv, extra)) __OTORP__(int argc;char *argv[]; __V_ *extra;){
114         register char *name;
115         register int r, flags=0, fd=0;
116         long timeout = 1000*sh.tmout;
117         int save_prompt;
118         NOT_USED(argc);
119         NOT_USED(extra);
120         while((r = optget(argv,sh_optread))) switch(r)
121         {
122             case 'A':
123                 flags |= A_FLAG;
124                 break;
125             case 't':
126                 timeout = 1000*opt_num;
127                 break;
128             case 'd':
129                 if(opt_arg && *opt_arg!='\n')
130                         flags |= ((*opt_arg)<< D_FLAG);
131                 break;
132             case 'p':
133                 if((fd = sh.cpipe[0])<=0)
134                         error(ERROR_exit(1),e_query);
135                 break;
136             case 'r':
137                 flags |= R_FLAG;
138                 break;
139             case 's':
140                 /* save in history file */
141                 flags |= S_FLAG;
142                 break;
143             case 'u':
144                 fd = (int)opt_num;
145                 if(sh_inuse(fd))
146                         fd = -1;
147                 break;
148             case ':':
149                 error(2, opt_arg);
150                 break;
151             case '?':
152                 error(ERROR_usage(2), opt_arg);
153                 break;
154         }
155         argv += opt_index;
156         if(error_info.errors)
157                 error(ERROR_usage(2),optusage((char*)0));
158         if(!((r=sh.fdstatus[fd])&IOREAD)  || !(r&(IOSEEK|IONOSEEK)))
159                 r = sh_iocheckfd(fd);
160         if(fd<0 || !(r&IOREAD))
161                 error(ERROR_system(1),e_file+4);
162         /* look for prompt */
163         if((name = *argv) && (name=strchr(name,'?')) && (r&IOTTY))
164         {
165                 r = strlen(++name)+1;
166                 if(sh.prompt=(char*)sfreserve(sfstderr,r,1))
167                 {
168                         memcpy(sh.prompt,name,r);
169                         sfwrite(sfstderr,sh.prompt,r);
170                 }
171         }
172         sh.timeout = 0;
173         save_prompt = sh.nextprompt;
174         sh.nextprompt = 0;
175         r=sh_readline(argv,fd,flags,timeout);
176         sh.nextprompt = save_prompt;
177         if(r==0 && (r=(sfeof(sh.sftable[fd])||sferror(sh.sftable[fd]))))
178         {
179                 if(fd == sh.cpipe[0])
180                 {
181                         sh_pclose(sh.cpipe);
182                         return(1);
183                 }
184         }
185         sfclrerr(sh.sftable[fd]);
186         return(r);
187 }
188
189 /*
190  * here for read timeout
191  */
192 static void timedout __PARAM__((__V_ *handle), (handle)) __OTORP__(__V_ *handle;){
193         sfclrlock((Sfio_t*)handle);
194         sh_exit(1);
195 }
196
197 /*
198  * This is the code to read a line and to split it into tokens
199  *  <names> is an array of variable names
200  *  <fd> is the file descriptor
201  *  <flags> is union of -A, -r, -s, and contains delimiter if not '\n'
202  *  <timeout> is number of milli-seconds until timeout
203  */
204
205 int sh_readline __PARAM__((char **names, int fd, int flags,long timeout), (names, fd, flags, timeout)) __OTORP__(char **names; int fd; int flags;long timeout;){
206         register int            c;
207         register unsigned char  *cp;
208         register Namval_t       *np;
209         register char           *name, *val;
210         register Sfio_t *iop;
211         char                    *ifs;
212         unsigned char           *cpmax;
213         char                    was_escape = 0;
214         char                    use_stak = 0;
215         int                     rel;
216         long                    array_index = 0;
217         __V_                    *timeslot=0;
218         int                     delim = '\n';
219         int                     jmpval=0;
220         struct  checkpt         buff;
221         if(!(iop=sh.sftable[fd]) && !(iop=sh_iostream(fd)))
222                 return(1);
223         if(flags>>D_FLAG)       /* delimiter not new-line */
224         {
225                 delim = ((unsigned)flags)>>D_FLAG;
226                 if(sh.fdstatus[fd]&IOTTY)
227                         tty_raw(fd,1);
228         }
229         /* set up state table based on IFS */
230         ifs = nv_getval(np=nv_scoped(IFSNOD));
231         if((flags&R_FLAG) && sh.ifstable['\\']==S_ESC)
232                 sh.ifstable['\\'] = 0;
233         else if(!(flags&R_FLAG) && sh.ifstable['\\']==0)
234                 sh.ifstable['\\'] = S_ESC;
235         sh.ifstable[delim] = S_NL;
236         if(delim!='\n')
237         {
238                 sh.ifstable['\n'] = 0;
239                 nv_putval(np, ifs, NV_RDONLY);
240         }
241         sh.ifstable[0] = S_EOF;
242         if(names && (name = *names))
243         {
244                 if(val= strchr(name,'?'))
245                         *val = 0;
246                 np = nv_open(name,sh.var_tree,NV_NOASSIGN|NV_VARNAME);
247                 if(flags&A_FLAG)
248                 {
249                         flags &= ~A_FLAG;
250                         array_index = 1;
251                         nv_unset(np);
252                         nv_putsub(np,NIL(char*),0L);
253                 }
254                 else
255                         name = *++names;
256                 if(val)
257                         *val = '?';
258         }
259         else
260         {
261                 name = 0;
262                 if(hashscope(sh.var_tree))
263                         np = nv_search((char*)REPLYNOD,sh.var_tree,HASH_BUCKET);
264                 else
265                         np = REPLYNOD;
266         }
267         sfclrerr(iop);
268         if(timeout)
269         {
270                 sh_pushcontext(&buff,1);
271                 jmpval = sigsetjmp(buff.buff,0);
272                 if(jmpval)
273                         goto done;
274                 timeslot = (__V_*)timeradd(timeout,0,timedout,(__V_*)iop);
275         }
276         if(!(cp = (unsigned char*)sfgetr(iop,delim,0)))
277                 cp = (unsigned char*)sfgetr(iop,delim,-1);
278         if(timeslot)
279                 timerdel(timeslot);
280         if(cp)
281         {
282                 cpmax = cp + sfslen();
283                 if(*(cpmax-1) != delim)
284                         *(cpmax-1) = delim;
285                 if(flags&S_FLAG)
286                         sfwrite(sh.hist_ptr->histfp,(char*)cp,sfslen());
287                 c = sh.ifstable[*cp++];
288 #ifndef SHOPT_MULTIBYTE
289                 if(!name && (flags&R_FLAG)) /* special case single argument */
290                 {
291                         /* skip over leading blanks */
292                         while(c==S_SPACE)
293                                 c = sh.ifstable[*cp++];
294                         /* strip trailing delimiters */
295                         if(cpmax[-1] == '\n')
296                                 cpmax--;
297                         *cpmax =0;
298                         if(cpmax>cp)
299                         {
300                                 while((c=sh.ifstable[*--cpmax])==S_DELIM || c==S_SPACE);
301                                 cpmax[1] = 0;
302                         }
303                         nv_putval(np,(char*)cp-1,0);
304                         goto done;
305                 }
306 #endif /* !SHOPT_MULTIBYTE */
307         }
308         else
309                 c = S_NL;
310         sh.nextprompt = 2;
311         rel= staktell();
312         /* val==0 at the start of a field */
313         val = 0;
314         while(1)
315         {
316                 switch(c)
317                 {
318 #ifdef SHOPT_MULTIBYTE
319                    case S_MBYTE:
320                         if(sh_strchr(ifs,(char*)cp-1)>=0)
321                         {
322                                 c = mblen((char*)cp-1,MB_CUR_MAX);
323                                 cp[-1] = 0;
324                                 cp += (c-1);
325                                 c = S_DELIM;
326                         }
327                         else
328                                 c = 0;
329                         continue;
330 #endif /*SHOPT_MULTIBYTE */
331                     case S_ESC:
332                         /* process escape character */
333                         if((c = sh.ifstable[*cp++]) == S_NL)
334                                 was_escape = 1;
335                         else
336                                 c = 0;
337                         if(val)
338                         {
339                                 stakputs(val);
340                                 use_stak = 1;
341                                 was_escape = 1;
342                                 *val = 0;
343                         }
344                         continue;
345
346                     case S_EOF:
347                         /* check for end of buffer */
348                         if(val && *val)
349                         {
350                                 stakputs(val);
351                                 use_stak = 1;
352                         }
353                         val = 0;
354                         if(cp>=cpmax)
355                         {
356                                 c = S_NL;
357                                 break;
358                         }
359                         /* eliminate null bytes */
360                         c = sh.ifstable[*cp++];
361                         if(!name && val && (c==S_SPACE||c==S_DELIM||c==S_MBYTE))
362                                 c = 0;
363                         continue;
364                     case S_NL:
365                         if(was_escape)
366                         {
367                                 was_escape = 0;
368                                 if((cp = (unsigned char*)sfgetr(iop,delim,0)) ||
369                                     (cp = (unsigned char*)sfgetr(iop,delim,-1)))
370                                 {
371                                         if(flags&S_FLAG)
372                                                 sfwrite(sh.hist_ptr->histfp,(char*)cp,sfslen());
373                                         cpmax = cp + sfslen();
374                                         c = sh.ifstable[*cp++];
375                                         val=0;
376                                         if(!name && (c==S_SPACE || c==S_DELIM || c==S_MBYTE))
377                                                 c = 0;
378                                         continue;
379                                 }
380                         }
381                         c = S_NL;
382                         break;
383
384                     case S_SPACE:
385                         /* skip over blanks */
386                         while(c==S_SPACE)
387                                 c = sh.ifstable[*cp++];
388                         if(!val)
389                                 continue;
390 #ifdef SHOPT_MULTIBYTE
391                         if(c==S_MBYTE)
392                         {
393                                 if(sh_strchr(ifs,(char*)cp-1)>=0)
394                                 {
395                                         c = mblen((char*)cp-1,MB_CUR_MAX);
396                                         cp += (c-1);
397                                         c = S_DELIM;
398                                 }
399                                 else
400                                         c = 0;
401                         }
402 #endif /* SHOPT_MULTIBYTE */
403                         if(c!=S_DELIM)
404                                 break;
405                         /* FALL THRU */
406                     case S_DELIM:
407                         if(name)
408                         {
409                                 /* skip over trailing blanks */
410                                 while((c=sh.ifstable[*cp++])==S_SPACE);
411                                 break;
412                         }
413
414                     case 0:
415                         was_escape = 0;
416                         val = (char*)(cp-1);
417                         /* skip over word characters */
418                         while(1)
419                         {
420                                 while((c=sh.ifstable[*cp++])==0);
421                                 if(name || c==S_NL || c==S_ESC || c==S_EOF || c==S_MBYTE)
422                                         break;
423                         }
424                         if(c!=S_MBYTE)
425                                 cp[-1] = 0;
426                         continue;
427                 }
428                 /* assign value and advance to next variable */
429                 if(!val)
430                         val = "";
431                 if(use_stak)
432                 {
433                         stakputs(val);
434                         stakputc(0);
435                         val = stakptr(rel);
436                 }
437                 if(!name && *val)
438                 {
439                         /* strip off trailing delimiters */
440                         register char   *cp = val + strlen(val);
441                         register int n;
442                         while((n=sh.ifstable[*--cp])==S_DELIM || n==S_SPACE);
443                         cp[1] = 0;
444                 }
445                 nv_putval(np,val,0);
446                 val = 0;
447                 if(use_stak)
448                 {
449                         stakseek(rel);
450                         use_stak = 0;
451                 }
452                 if(array_index)
453                 {
454                         nv_putsub(np, NIL(char*), array_index++);
455                         if(c!=S_NL)
456                                 continue;
457                         name = *++names;
458                 }
459                 while(1)
460                 {
461                         if(sh_isoption(SH_ALLEXPORT)&&!strchr(nv_name(np),'.'))
462                                 nv_onattr(np,NV_EXPORT);
463                         if(name)
464                         {
465                                 nv_close(np);
466                                 np = nv_open(name,sh.var_tree,NV_NOASSIGN|NV_VARNAME);
467                                 name = *++names;
468                         }
469                         else
470                                 np = 0;
471                         if(c!=S_NL)
472                                 break;
473                         if(!np)
474                                 goto done;
475                         nv_putval(np, "", 0);
476                 }
477         }
478 done:
479         nv_close(np);
480         if(timeout)
481                 sh_popcontext(&buff);
482         if((flags>>D_FLAG) && (sh.fdstatus[fd]&IOTTY))
483                 tty_cooked(fd);
484         if(flags&S_FLAG)
485                 hist_flush(sh.hist_ptr);
486         return(jmpval);
487 }
488