This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.bin / more / os.c
CommitLineData
2ec5f51d
NW
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, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef lint
36static char sccsid[] = "@(#)os.c 5.12 (Berkeley) 3/1/91";
37#endif /* not lint */
38
39/*
40 * Operating system dependent routines.
41 *
42 * Most of the stuff in here is based on Unix, but an attempt
43 * has been made to make things work on other operating systems.
44 * This will sometimes result in a loss of functionality, unless
45 * someone rewrites code specifically for the new operating system.
46 *
47 * The makefile provides defines to decide whether various
48 * Unix features are present.
49 */
50
51#include <sys/param.h>
52#include <sys/stat.h>
53#include <sys/file.h>
54#include <signal.h>
55#include <setjmp.h>
56#include <stdio.h>
57#include <less.h>
58#include "pathnames.h"
59
60int reading;
61
62extern int screen_trashed;
63
64static jmp_buf read_label;
65
66/*
67 * Pass the specified command to a shell to be executed.
68 * Like plain "system()", but handles resetting terminal modes, etc.
69 */
70lsystem(cmd)
71 char *cmd;
72{
73 int inp;
74 char cmdbuf[256];
75 char *shell, *getenv();
76
77 /*
78 * Print the command which is to be executed,
79 * unless the command starts with a "-".
80 */
81 if (cmd[0] == '-')
82 cmd++;
83 else
84 {
85 lower_left();
86 clear_eol();
87 putstr("!");
88 putstr(cmd);
89 putstr("\n");
90 }
91
92 /*
93 * De-initialize the terminal and take out of raw mode.
94 */
95 deinit();
96 flush();
97 raw_mode(0);
98
99 /*
100 * Restore signals to their defaults.
101 */
102 init_signals(0);
103
104 /*
105 * Force standard input to be the terminal, "/dev/tty",
106 * even if less's standard input is coming from a pipe.
107 */
108 inp = dup(0);
109 (void)close(0);
110 if (open(_PATH_TTY, O_RDONLY, 0) < 0)
111 (void)dup(inp);
112
113 /*
114 * Pass the command to the system to be executed.
115 * If we have a SHELL environment variable, use
116 * <$SHELL -c "command"> instead of just <command>.
117 * If the command is empty, just invoke a shell.
118 */
119 if ((shell = getenv("SHELL")) != NULL && *shell != '\0')
120 {
121 if (*cmd == '\0')
122 cmd = shell;
123 else
124 {
125 (void)sprintf(cmdbuf, "%s -c \"%s\"", shell, cmd);
126 cmd = cmdbuf;
127 }
128 }
129 if (*cmd == '\0')
130 cmd = "sh";
131
132 (void)system(cmd);
133
134 /*
135 * Restore standard input, reset signals, raw mode, etc.
136 */
137 (void)close(0);
138 (void)dup(inp);
139 (void)close(inp);
140
141 init_signals(1);
142 raw_mode(1);
143 init();
144 screen_trashed = 1;
145#if defined(SIGWINCH) || defined(SIGWIND)
146 /*
147 * Since we were ignoring window change signals while we executed
148 * the system command, we must assume the window changed.
149 */
150 winch();
151#endif
152}
153
154/*
155 * Like read() system call, but is deliberately interruptable.
156 * A call to intread() from a signal handler will interrupt
157 * any pending iread().
158 */
159iread(fd, buf, len)
160 int fd;
161 char *buf;
162 int len;
163{
164 register int n;
165
166 if (setjmp(read_label))
167 /*
168 * We jumped here from intread.
169 */
170 return (READ_INTR);
171
172 flush();
173 reading = 1;
174 n = read(fd, buf, len);
175 reading = 0;
176 if (n < 0)
177 return (-1);
178 return (n);
179}
180
181intread()
182{
183 (void)sigsetmask(0L);
184 longjmp(read_label, 1);
185}
186
187/*
188 * Expand a filename, substituting any environment variables, etc.
189 * The implementation of this is necessarily very operating system
190 * dependent. This implementation is unabashedly only for Unix systems.
191 */
192FILE *popen();
193
194char *
195glob(filename)
196 char *filename;
197{
198 FILE *f;
199 char *p;
200 int ch;
201 char *cmd, *malloc(), *getenv();
202 static char buffer[MAXPATHLEN];
203
204 if (filename[0] == '#')
205 return (filename);
206
207 /*
208 * We get the shell to expand the filename for us by passing
209 * an "echo" command to the shell and reading its output.
210 */
211 p = getenv("SHELL");
212 if (p == NULL || *p == '\0')
213 {
214 /*
215 * Read the output of <echo filename>.
216 */
217 cmd = malloc((u_int)(strlen(filename)+8));
218 if (cmd == NULL)
219 return (filename);
220 (void)sprintf(cmd, "echo \"%s\"", filename);
221 } else
222 {
223 /*
224 * Read the output of <$SHELL -c "echo filename">.
225 */
226 cmd = malloc((u_int)(strlen(p)+12));
227 if (cmd == NULL)
228 return (filename);
229 (void)sprintf(cmd, "%s -c \"echo %s\"", p, filename);
230 }
231
232 if ((f = popen(cmd, "r")) == NULL)
233 return (filename);
234 free(cmd);
235
236 for (p = buffer; p < &buffer[sizeof(buffer)-1]; p++)
237 {
238 if ((ch = getc(f)) == '\n' || ch == EOF)
239 break;
240 *p = ch;
241 }
242 *p = '\0';
243 (void)pclose(f);
244 return(buffer);
245}
246
247char *
248bad_file(filename, message, len)
249 char *filename, *message;
250 u_int len;
251{
252 extern int errno;
253 struct stat statbuf;
254 char *strcat(), *strerror();
255
256 if (stat(filename, &statbuf) < 0) {
257 (void)sprintf(message, "%s: %s", filename, strerror(errno));
258 return(message);
259 }
260 if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
261 static char is_dir[] = " is a directory";
262
263 strtcpy(message, filename, (int)(len-sizeof(is_dir)-1));
264 (void)strcat(message, is_dir);
265 return(message);
266 }
267 return((char *)NULL);
268}
269
270/*
271 * Copy a string, truncating to the specified length if necessary.
272 * Unlike strncpy(), the resulting string is guaranteed to be null-terminated.
273 */
274strtcpy(to, from, len)
275 char *to, *from;
276 int len;
277{
278 char *strncpy();
279
280 (void)strncpy(to, from, (int)len);
281 to[len-1] = '\0';
282}
283