less -> more
[unix-history] / usr / src / usr.bin / more / os.c
CommitLineData
bfe13c81
KB
1/*
2 * Copyright (c) 1988 Mark Nudleman
3 * Copyright (c) 1988 Regents of the University of California.
4 * All rights reserved.
5 *
bfe13c81
KB
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
a942b40b
KB
11 * by Mark Nudleman and the University of California, Berkeley. The
12 * name of Mark Nudleman or the
bfe13c81
KB
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
a942b40b 21static char sccsid[] = "@(#)os.c 5.8 (Berkeley) %G%";
bfe13c81
KB
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
41char *getenv();
42
43public int reading;
44
45extern int screen_trashed;
46
47static 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
54lsystem(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 {
898d24ca 109 (void)sprintf(cmdbuf, "%s -c \"%s\"", shell, cmd);
bfe13c81
KB
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
144iread(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
167intread()
168{
8e70b0c4 169 sigsetmask(0L);
bfe13c81
KB
170 longjmp(read_label, 1);
171}
172
bfe13c81
KB
173 public long
174get_time()
175{
54795006 176 time_t time();
bfe13c81 177
54795006 178 return(time((long *)NULL));
bfe13c81 179}
bfe13c81
KB
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 */
bfe13c81
KB
186FILE *popen();
187
188 public char *
189glob(filename)
190 char *filename;
191{
192 FILE *f;
193 char *p;
194 int ch;
898d24ca 195 char *cmd, *malloc();
bfe13c81
KB
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 */
898d24ca 211 cmd = malloc((u_int)(strlen(filename)+8));
bfe13c81
KB
212 if (cmd == NULL)
213 return (filename);
898d24ca 214 (void)sprintf(cmd, "echo \"%s\"", filename);
bfe13c81
KB
215 } else
216 {
217 /*
218 * Read the output of <$SHELL -c "echo filename">.
219 */
898d24ca 220 cmd = malloc((u_int)(strlen(p)+12));
bfe13c81
KB
221 if (cmd == NULL)
222 return (filename);
898d24ca 223 (void)sprintf(cmd, "%s -c \"echo %s\"", p, filename);
bfe13c81
KB
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
bfe13c81
KB
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
bfe13c81
KB
247#include <sys/types.h>
248#include <sys/stat.h>
249
250 public char *
251bad_file(filename, message, len)
252 char *filename;
253 char *message;
254 unsigned int len;
255{
256 struct stat statbuf;
898d24ca 257 char *strcat();
bfe13c81
KB
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);
898d24ca 266 (void)strcat(message, is_dir);
bfe13c81
KB
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);
898d24ca 273 (void)strcat(message, not_reg);
bfe13c81
KB
274 return (message);
275 }
276 return (NULL);
277}
278
bfe13c81
KB
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
bfe13c81
KB
285extern char *sys_errlist[];
286extern int sys_nerr;
287extern int errno;
288
289 public char *
290errno_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 {
898d24ca 302 (void)sprintf(msg, "Error %d", errno);
bfe13c81
KB
303 p = msg;
304 }
305 strtcpy(message, filename, len-strlen(p)-3);
898d24ca
KB
306 (void)strcat(message, ": ");
307 (void)strcat(message, p);
bfe13c81
KB
308 return (message);
309}