1 /* @(#)edit.c	1.40 19/04/27 Copyright 2006-2019 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)edit.c	1.40 19/04/27 Copyright 2006-2019 J. Schilling";
6 #endif
7 /*
8  *	Copyright (c) 2006-2019 J. Schilling
9  */
10 /*
11  * The contents of this file are subject to the terms of the
12  * Common Development and Distribution License, Version 1.0 only
13  * (the "License").  You may not use this file except in compliance
14  * with the License.
15  *
16  * See the file CDDL.Schily.txt in this distribution for details.
17  * A copy of the CDDL is also available via the Internet at
18  * http://www.opensource.org/licenses/cddl1.txt
19  *
20  * When distributing Covered Code, include this CDDL HEADER in each
21  * file and include the License file CDDL.Schily.txt from this distribution.
22  */
23 
24 #include <schily/unistd.h>
25 #include <schily/varargs.h>
26 #include <schily/fcntl.h>
27 #include <schily/stat.h>
28 #include <schily/stdio.h>
29 #include "bsh.h"
30 #include "strsubs.h"
31 #include <schily/fstream.h>
32 #include <schily/shedit.h>
33 #define	toint		shell_toint
34 
35 LOCAL fstream	*instrm = (fstream *) NULL;	/* Aliasexpanded input stream */
36 LOCAL fstream	*rawstrm = (fstream *) NULL;	/* Unexpanded input stream */
37 
38 LOCAL	void	einit		__PR((void));
39 LOCAL	int	readchar	__PR((fstream *fsp));
40 EXPORT	int	shedit_egetc	__PR((void));
41 EXPORT	int	shedit_getdelim	__PR((void));
42 EXPORT	void	shedit_treset	__PR((void));
43 EXPORT	void	shedit_bhist	__PR((int **ctlcpp));
44 EXPORT	void	shedit_bshist	__PR((int **ctlcpp));
45 LOCAL	int	lstatat	__PR((char *name, struct stat *buf, int flag));
46 
47 /*
48  * Set up file from where the inout should be read,
49  * returns the old FILE * value.
50  */
51 EXPORT FILE *
setinput(f)52 setinput(f)
53 	FILE	*f;
54 {
55 	if (rawstrm == (fstream *) NULL)
56 		rawstrm = mkfstream(f,
57 				(fstr_fun)0, readchar, (fstr_efun)berror);
58 	else
59 		f = fssetfile(rawstrm, f);
60 
61 	if (instrm == (fstream *) NULL)			/* Pfusch in sgetc */
62 		instrm = mkfstream((FILE *)rawstrm,
63 				NULL, (fstr_rfun)0, (fstr_efun)berror);
64 	return (f);
65 }
66 
67 extern  char    **environ;
68 extern	int	delim;
69 extern	int	prompt;
70 extern	char	*inithome;
71 
72 #ifndef	LIB_SHEDIT
73 int
main(ac,av,ev)74 main(ac, av, ev)
75 	int	ac;
76 	char	*av[];
77 	char	*ev[];
78 {
79 	editloop();
80 }
81 #endif
82 
83 LOCAL	int	__init;
84 
85 LOCAL void
einit()86 einit()
87 {
88 	char	*p;
89 	FILE	*f;
90 
91 	gstd[0] = stdin;
92 	gstd[1] = stdout;
93 	gstd[2] = stderr;
94 	evarray = environ;
95 
96 	p = getcurenv("HOME");
97 	if (p)
98 		inithome = p;
99 
100 	/*
101 	 * Use stdin only as a fallback if the input was not yet set.
102 	 */
103 	f = setinput(stdin);
104 	if (f != stdin)
105 		setinput(f);
106 	init_input();
107 	read_init_history();
108 	__init = TRUE;
109 }
110 
111 LOCAL int
readchar(fsp)112 readchar(fsp)
113 	register fstream	*fsp;
114 {
115 #ifdef	INTERACTIVE
116 extern	int	ttyflg;
117 extern	int	prflg;
118 
119 	prflg = ttyflg = isatty(fdown(fsp->fstr_file));
120 	pushline(get_line(prompt++, fsp->fstr_file));
121 	return (fsgetc(fsp));
122 #else
123 	return (getc(fsp->fstr_file));	/* read from FILE */
124 #endif
125 }
126 
127 EXPORT int
shedit_egetc()128 shedit_egetc()
129 {
130 	if (!__init)
131 		einit();
132 	return (fsgetc(rawstrm));
133 }
134 
135 EXPORT size_t
shedit_getlen()136 shedit_getlen()
137 {
138 	if (!__init)
139 		einit();
140 	return (fsgetlen(rawstrm));
141 }
142 
143 EXPORT int
shedit_getdelim()144 shedit_getdelim()
145 {
146 	return (delim);
147 }
148 
149 #ifndef	LIB_SHEDIT
editloop()150 editloop()
151 {
152 	int	c;
153 	int	i = 0;
154 
155 	while (c = shedit_egetc()) {
156 		printf("%c %o\n", c, c);
157 		if (c == '\r' || c == '\n') {
158 			printf("prompt %d\n", prompt);
159 			prompt = 0;
160 		}
161 	if (++i > 100)
162 		break;
163 	}
164 	exitbsh(0);
165 	return (0);
166 }
167 #endif
168 
169 EXPORT BOOL
toint(std,s,i)170 toint(std, s, i)
171 	FILE	*std[];
172 	char	*s;
173 	int	*i;
174 {
175 	if (*s == '\0' || *astoi(s, i)) {
176 		fprintf(std[2], "Not a number: %s.\n", s);
177 		ex_status = 1;
178 		return (FALSE);
179 	}
180 	return (TRUE);
181 }
182 
183 char	*
myhome()184 myhome()
185 {
186 	return (makestr(inithome));
187 }
188 
189 #ifdef	PROTOTYPES
190 EXPORT int
berror(const char * s,...)191 berror(const char *s, ...)
192 #else
193 /* VARARGS1 */
194 EXPORT int
195 berror(s, va_alist)
196 	char	*s;
197 	va_dcl
198 #endif
199 {
200 	va_list	args;
201 	int	ret;
202 
203 #ifdef	PROTOTYPES
204 	va_start(args, s);
205 #else
206 	va_start(args);
207 #endif
208 	ret = fprintf(stderr, "%r\n", s, args);
209 	va_end(args);
210 	(void) fflush(stderr);
211 	return (ret);
212 }
213 
214 
215 #if defined(__BEOS__) || defined(__HAIKU__)
216 #define	silent_error(e)		((e) < 0 && (e) >= -1024)
217 #else
218 #define	silent_error(e)		((e) < 0)
219 #endif
220 
221 EXPORT char *
errstr(err)222 errstr(err)
223 	int	err;
224 {
225 	static	char	errbuf[12];
226 	char	*estr;
227 
228 	if (silent_error(err)) {
229 		return ("");
230 	} else {
231 		estr = errmsgstr(err);
232 		if (estr == NULL) {
233 			sprintf(errbuf, "%d", err);
234 			estr = errbuf;
235 		}
236 		return (estr);
237 	}
238 }
239 
240 /*
241  * Push back a complete line
242  */
243 EXPORT void
pushline(s)244 pushline(s)
245 	char	*s;
246 {
247 	if (s && rawstrm != (fstream *) NULL) {
248 		fspushcha(rawstrm, delim);
249 		fspushstr(rawstrm, s);
250 	}
251 }
252 
253 /*
254  * Check the current environment array against name and tval.
255  */
256 EXPORT BOOL
ev_eql(name,tval)257 ev_eql(name, tval)
258 	char	*name;
259 	char	*tval;
260 {
261 	char	*val;
262 
263 	if ((val = getcurenv(name)) != NULL)
264 		return (streql(val, tval));
265 	return (FALSE);
266 }
267 
268 EXPORT BOOL
is_dir(name)269 is_dir(name)
270 	char	*name;
271 {
272 	struct	stat	buf;
273 
274 	if (lstatat(name, &buf, 0) < 0)
275 		return (FALSE);
276 
277 	return ((buf.st_mode & S_IFMT) == S_IFDIR);
278 }
279 
280 
281 EXPORT void
exitbsh(excode)282 exitbsh(excode)
283 	int	excode;
284 {
285 int	sflg = 1;
286 
287 	if (sflg) {
288 						/* see if its a top level */
289 						/* run final file */
290 #ifdef	INTERACTIVE
291 		save_history(HI_NOINTR);
292 #endif
293 	}
294 
295 #ifdef	INTERACTIVE
296 	reset_tty_modes();
297 	reset_line_disc();		/* Line discipline */
298 	reset_tty_pgrp();
299 #endif
300 	exit(excode);
301 }
302 
303 EXPORT void
shedit_treset()304 shedit_treset()
305 {
306 	save_history(HI_NOINTR);
307 	reset_tty_modes();
308 	reset_line_disc();		/* Line discipline */
309 	reset_tty_pgrp();
310 }
311 
312 EXPORT void
shedit_bhist(ctlcpp)313 shedit_bhist(ctlcpp)
314 	int	**ctlcpp;
315 {
316 	if (ctlcpp)
317 		*ctlcpp = &ctlc;
318 	ctlc = 0;
319 	put_history(gstd[1], HI_INTR, 0, 0, NULL);
320 }
321 
322 EXPORT int
shedit_history(f,ctlcpp,flags,first,last,subst)323 shedit_history(f, ctlcpp, flags, first, last, subst)
324 	FILE	*f;
325 	int	**ctlcpp;
326 	int	flags;
327 	int	first;
328 	int	last;
329 	char	*subst;
330 {
331 	if (ctlcpp)
332 		*ctlcpp = &ctlc;
333 	ctlc = 0;
334 	return (put_history(f?f:gstd[1], flags, first, last, subst));
335 }
336 
337 EXPORT int
shedit_search_history(ctlcpp,flags,first,pat)338 shedit_search_history(ctlcpp, flags, first, pat)
339 	int	**ctlcpp;
340 	int	flags;
341 	int	first;
342 	char	*pat;
343 {
344 	if (ctlcpp)
345 		*ctlcpp = &ctlc;
346 	ctlc = 0;
347 	return (search_history(flags, first, pat));
348 }
349 
350 EXPORT int
shedit_remove_history(ctlcpp,flags,first,pat)351 shedit_remove_history(ctlcpp, flags, first, pat)
352 	int	**ctlcpp;
353 	int	flags;
354 	int	first;
355 	char	*pat;
356 {
357 	if (ctlcpp)
358 		*ctlcpp = &ctlc;
359 	ctlc = 0;
360 	return (remove_history(flags, first, pat));
361 }
362 
363 EXPORT int
shedit_read_history(f,ctlcpp,flags)364 shedit_read_history(f, ctlcpp, flags)
365 	FILE	*f;
366 	int	**ctlcpp;
367 	int	flags;
368 {
369 	if (ctlcpp)
370 		*ctlcpp = &ctlc;
371 	ctlc = 0;
372 	shell_readhistory(f);
373 	return (0);
374 }
375 
376 EXPORT void
shedit_bshist(ctlcpp)377 shedit_bshist(ctlcpp)
378 	int	**ctlcpp;
379 {
380 	if (ctlcpp)
381 		*ctlcpp = &ctlc;
382 	ctlc = 0;
383 	save_history(HI_INTR);
384 }
385 
386 EXPORT char *
shell_getenv(name)387 shell_getenv(name)
388 	char	*name;
389 {
390 	extern	char	*(*__get_env)	__PR((char *__name));
391 
392 	if (name == NULL)
393 		return ((char *)NULL);
394 	if (__get_env != NULL)
395 		return (__get_env(name));
396 	return (getenv(name));
397 }
398 
399 EXPORT void
shell_putenv(name)400 shell_putenv(name)
401 	char	*name;
402 {
403 	extern	void	(*__put_env)	__PR((char *__name));
404 
405 	if (name == NULL)
406 		return;
407 	if (__put_env != NULL)
408 		__put_env(name);
409 	else
410 		putenv(name);
411 }
412 
413 EXPORT void
414 shedit_getenv(genv)
415 	char	*(*genv) __PR((char *name));
416 {
417 	extern	char	*(*__get_env)	__PR((char *__name));
418 
419 	__get_env = genv;
420 }
421 
422 EXPORT void
423 shedit_putenv(penv)
424 	void	(*penv) __PR((char *name));
425 {
426 	extern	void	(*__put_env)	__PR((char *__name));
427 
428 	__put_env = penv;
429 }
430 
431 EXPORT void
432 shedit_igneof(ieof)
433 	BOOL	(*ieof) __PR((void));
434 {
435 	extern	BOOL	(*__ign_eof)	__PR((void));
436 
437 	__ign_eof = ieof;
438 }
439 
440 EXPORT void
shedit_setprompts(promptidx,nprompts,newprompts)441 shedit_setprompts(promptidx, nprompts, newprompts)
442 	int	promptidx;
443 	int	nprompts;
444 	char	*newprompts[];
445 {
446 	int	i;
447 
448 	prompt = promptidx;
449 
450 	if (nprompts > SHEDIT_NPROMPTS)
451 		nprompts = SHEDIT_NPROMPTS;
452 
453 	for (i = 0; i < nprompts; i++)
454 		prompts[i] = newprompts[i];
455 }
456 
457 EXPORT void
shedit_spromptidx(promptidx)458 shedit_spromptidx(promptidx)
459 	int	promptidx;
460 {
461 	prompt = promptidx;
462 
463 	if (prompt >= SHEDIT_NPROMPTS)
464 		prompt = SHEDIT_NPROMPTS-1;
465 }
466 
467 EXPORT int
shedit_gpromptidx()468 shedit_gpromptidx()
469 {
470 	return (prompt);
471 }
472 
473 LOCAL int
lstatat(name,buf,flag)474 lstatat(name, buf, flag)
475 	char		*name;
476 	struct stat	*buf;
477 	int		flag;
478 {
479 #ifdef	HAVE_FCHDIR
480 	char	*p;
481 	int	fd;
482 	int	err;
483 #endif
484 	int	ret;
485 
486 	if ((ret = fstatat(AT_FDCWD, name, buf, flag)) < 0 &&
487 	    geterrno() != ENAMETOOLONG) {
488 		return (ret);
489 	}
490 
491 #ifdef	HAVE_FCHDIR
492 	if (ret >= 0)
493 		return (ret);
494 
495 	fd = bsh_hop_dirs(name, &p);
496 	ret = fstatat(fd, p, buf, flag);
497 	err = geterrno();
498 	close(fd);
499 	seterrno(err);
500 #endif
501 	return (ret);
502 }
503