Commit | Line | Data |
---|---|---|
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 | 21 | static 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 | ||
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 | { | |
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 | |
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 | { | |
8e70b0c4 | 169 | sigsetmask(0L); |
bfe13c81 KB |
170 | longjmp(read_label, 1); |
171 | } | |
172 | ||
bfe13c81 KB |
173 | public long |
174 | get_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 |
186 | FILE *popen(); |
187 | ||
188 | public char * | |
189 | glob(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 * | |
251 | bad_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 |
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 | { | |
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 | } |