xref: /original-bsd/usr.bin/more/os.c (revision 823023b8)
1 /*
2  * Copyright (c) 1988 Mark Nudleman
3  * Copyright (c) 1988 Regents of the University of California.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted
7  * provided that the above copyright notice and this paragraph are
8  * duplicated in all such forms and that any documentation,
9  * advertising materials, and other materials related to such
10  * distribution and use acknowledge that the software was developed
11  * by Mark Nudleman and the University of California, Berkeley.  The
12  * name of Mark Nudleman or the
13  * University may not be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  */
19 
20 #ifndef lint
21 static char sccsid[] = "@(#)os.c	5.8 (Berkeley) 07/25/88";
22 #endif /* not lint */
23 
24 /*
25  * Operating system dependent routines.
26  *
27  * Most of the stuff in here is based on Unix, but an attempt
28  * has been made to make things work on other operating systems.
29  * This will sometimes result in a loss of functionality, unless
30  * someone rewrites code specifically for the new operating system.
31  *
32  * The makefile provides defines to decide whether various
33  * Unix features are present.
34  */
35 
36 #include <stdio.h>
37 #include <signal.h>
38 #include <setjmp.h>
39 #include "less.h"
40 
41 char *getenv();
42 
43 public int reading;
44 
45 extern int screen_trashed;
46 
47 static jmp_buf read_label;
48 
49 /*
50  * Pass the specified command to a shell to be executed.
51  * Like plain "system()", but handles resetting terminal modes, etc.
52  */
53 	public void
54 lsystem(cmd)
55 	char *cmd;
56 {
57 	int inp;
58 	char cmdbuf[256];
59 	char *shell;
60 
61 	/*
62 	 * Print the command which is to be executed,
63 	 * unless the command starts with a "-".
64 	 */
65 	if (cmd[0] == '-')
66 		cmd++;
67 	else
68 	{
69 		lower_left();
70 		clear_eol();
71 		putstr("!");
72 		putstr(cmd);
73 		putstr("\n");
74 	}
75 
76 	/*
77 	 * De-initialize the terminal and take out of raw mode.
78 	 */
79 	deinit();
80 	flush();
81 	raw_mode(0);
82 
83 	/*
84 	 * Restore signals to their defaults.
85 	 */
86 	init_signals(0);
87 
88 	/*
89 	 * Force standard input to be the terminal, "/dev/tty",
90 	 * even if less's standard input is coming from a pipe.
91 	 */
92 	inp = dup(0);
93 	close(0);
94 	if (open("/dev/tty", 0) < 0)
95 		dup(inp);
96 
97 	/*
98 	 * Pass the command to the system to be executed.
99 	 * If we have a SHELL environment variable, use
100 	 * <$SHELL -c "command"> instead of just <command>.
101 	 * If the command is empty, just invoke a shell.
102 	 */
103 	if ((shell = getenv("SHELL")) != NULL && *shell != '\0')
104 	{
105 		if (*cmd == '\0')
106 			cmd = shell;
107 		else
108 		{
109 			(void)sprintf(cmdbuf, "%s -c \"%s\"", shell, cmd);
110 			cmd = cmdbuf;
111 		}
112 	}
113 	if (*cmd == '\0')
114 		cmd = "sh";
115 
116 	system(cmd);
117 
118 	/*
119 	 * Restore standard input, reset signals, raw mode, etc.
120 	 */
121 	close(0);
122 	dup(inp);
123 	close(inp);
124 
125 	init_signals(1);
126 	raw_mode(1);
127 	init();
128 	screen_trashed = 1;
129 #if defined(SIGWINCH) || defined(SIGWIND)
130 	/*
131 	 * Since we were ignoring window change signals while we executed
132 	 * the system command, we must assume the window changed.
133 	 */
134 	winch();
135 #endif
136 }
137 
138 /*
139  * Like read() system call, but is deliberately interruptable.
140  * A call to intread() from a signal handler will interrupt
141  * any pending iread().
142  */
143 	public int
144 iread(fd, buf, len)
145 	int fd;
146 	char *buf;
147 	int len;
148 {
149 	register int n;
150 
151 	if (setjmp(read_label))
152 		/*
153 		 * We jumped here from intread.
154 		 */
155 		return (READ_INTR);
156 
157 	flush();
158 	reading = 1;
159 	n = read(fd, buf, len);
160 	reading = 0;
161 	if (n < 0)
162 		return (-1);
163 	return (n);
164 }
165 
166 	public void
167 intread()
168 {
169 	sigsetmask(0L);
170 	longjmp(read_label, 1);
171 }
172 
173 	public long
174 get_time()
175 {
176 	time_t time();
177 
178 	return(time((long *)NULL));
179 }
180 
181 /*
182  * Expand a filename, substituting any environment variables, etc.
183  * The implementation of this is necessarily very operating system
184  * dependent.  This implementation is unabashedly only for Unix systems.
185  */
186 FILE *popen();
187 
188 	public char *
189 glob(filename)
190 	char *filename;
191 {
192 	FILE *f;
193 	char *p;
194 	int ch;
195 	char *cmd, *malloc();
196 	static char buffer[FILENAME];
197 
198 	if (filename[0] == '#')
199 		return (filename);
200 
201 	/*
202 	 * We get the shell to expand the filename for us by passing
203 	 * an "echo" command to the shell and reading its output.
204 	 */
205 	p = getenv("SHELL");
206 	if (p == NULL || *p == '\0')
207 	{
208 		/*
209 		 * Read the output of <echo filename>.
210 		 */
211 		cmd = malloc((u_int)(strlen(filename)+8));
212 		if (cmd == NULL)
213 			return (filename);
214 		(void)sprintf(cmd, "echo \"%s\"", filename);
215 	} else
216 	{
217 		/*
218 		 * Read the output of <$SHELL -c "echo filename">.
219 		 */
220 		cmd = malloc((u_int)(strlen(p)+12));
221 		if (cmd == NULL)
222 			return (filename);
223 		(void)sprintf(cmd, "%s -c \"echo %s\"", p, filename);
224 	}
225 
226 	if ((f = popen(cmd, "r")) == NULL)
227 		return (filename);
228 	free(cmd);
229 
230 	for (p = buffer;  p < &buffer[sizeof(buffer)-1];  p++)
231 	{
232 		if ((ch = getc(f)) == '\n' || ch == EOF)
233 			break;
234 		*p = ch;
235 	}
236 	*p = '\0';
237 	pclose(f);
238 	return (buffer);
239 }
240 
241 /*
242  * Returns NULL if the file can be opened and
243  * is an ordinary file, otherwise an error message
244  * (if it cannot be opened or is a directory, etc.)
245  */
246 
247 #include <sys/types.h>
248 #include <sys/stat.h>
249 
250 	public char *
251 bad_file(filename, message, len)
252 	char *filename;
253 	char *message;
254 	unsigned int len;
255 {
256 	struct stat statbuf;
257 	char *strcat();
258 
259 	if (stat(filename, &statbuf) < 0)
260 		return (errno_message(filename, message, len));
261 
262 	if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
263 	{
264 		static char is_dir[] = " is a directory";
265 		strtcpy(message, filename, len-sizeof(is_dir)-1);
266 		(void)strcat(message, is_dir);
267 		return (message);
268 	}
269 	if ((statbuf.st_mode & S_IFMT) != S_IFREG)
270 	{
271 		static char not_reg[] = " is not a regular file";
272 		strtcpy(message, filename, len-sizeof(not_reg)-1);
273 		(void)strcat(message, not_reg);
274 		return (message);
275 	}
276 	return (NULL);
277 }
278 
279 /*
280  * errno_message: Return an error message based on the value of "errno".
281  * okreadfail: Return true if the previous failure of a read
282  *	(on the input tty) should be considered ok.
283  */
284 
285 extern char *sys_errlist[];
286 extern int sys_nerr;
287 extern int errno;
288 
289 	public char *
290 errno_message(filename, message, len)
291 	char *filename;
292 	char *message;
293 	unsigned int len;
294 {
295 	char *p;
296 	char msg[16];
297 
298 	if (errno < sys_nerr)
299 		p = sys_errlist[errno];
300 	else
301 	{
302 		(void)sprintf(msg, "Error %d", errno);
303 		p = msg;
304 	}
305 	strtcpy(message, filename, len-strlen(p)-3);
306 	(void)strcat(message, ": ");
307 	(void)strcat(message, p);
308 	return (message);
309 }
310