1 /****************************************************************
2  * unshar.c: Unpackage one or more shell archive files
3  *
4  * Description:	unshar is a filter which removes the front part
5  *		of a file and passes the rest to the 'sh' command.
6  *		It understands phrases like "cut here", and also
7  *		knows about shell comment characters and the Unix
8  *		commands "echo", "cat", and "sed".
9  *
10  * HISTORY
11  *  27-July-88  Kim F. Storm (storm@texas.dk) Texas Instruments, Denmark
12  *	Adapted to :unshar command in nn
13  *	Added static to function declarations
14  *	Removed all unused functions, i.e. not useful as stand-alone pgm.
15  * 29-Jan-85  Michael Mauldin (mlm) at Carnegie-Mellon University
16  *	Created.
17  ****************************************************************/
18 
19 #include "config.h"
20 #include "global.h"
21 #include "nn_term.h"
22 
23 /* unshar.c */
24 
25 static int      stlmatch(char *big, char *small);
26 static int      smatch(register char *dat, register char *pat, register char **res);
27 
28 extern long     ftell();
29 
30 
31 /*****************************************************************
32  * stlmatch  --  match leftmost part of string
33  *
34  * Usage:  i = stlmatch (big,small)
35  *	int i;
36  *	char *small, *big;
37  *
38  * Returns 1 iff initial characters of big match small exactly;
39  * else 0.
40  *
41  * HISTORY
42  * 18-May-82 Michael Mauldin (mlm) at Carnegie-Mellon University
43  *      Ripped out of CMU lib for Rog-O-Matic portability
44  * 20-Nov-79  Steven Shafer (sas) at Carnegie-Mellon University
45  *	Rewritten for VAX from Ken Greer's routine.
46  *
47  *  Originally from klg (Ken Greer) on IUS/SUS UNIX
48  *****************************************************************/
49 
50 static int
stlmatch(char * big,char * small)51 stlmatch(char *big, char *small)
52 {
53     register char  *s, *b;
54     s = small;
55     b = big;
56     do {
57 	if (*s == '\0')
58 	    return (1);
59     }
60     while (*s++ == *b++);
61     return (0);
62 }
63 
64 /*****************************************************************
65  * smatch: Given a data string and a pattern containing one or
66  * more embedded stars (*) (which match any number of characters)
67  * return true if the match succeeds, and set res[i] to the
68  * characters matched by the 'i'th *.
69  *****************************************************************/
70 
71 static int
smatch(register char * dat,register char * pat,register char ** res)72 smatch(register char *dat, register char *pat, register char **res)
73 {
74     register char  *star = 0, *starend = 0, *resp = 0;
75     int             nres = 0;
76 
77     while (1) {
78 	if (*pat == '*') {
79 	    star = ++pat;	/* Pattern after * */
80 	    starend = dat;	/* Data after * match */
81 	    resp = res[nres++];	/* Result string */
82 	    *resp = '\0';	/* Initially null */
83 	} else if (*dat == *pat) {	/* Characters match */
84 	    if (*pat == '\0')	/* Pattern matches */
85 		return (1);
86 	    pat++;		/* Try next position */
87 	    dat++;
88 	} else {
89 	    if (*dat == '\0')	/* Pattern fails - no more */
90 		return (0);	/* data */
91 	    if (star == 0)	/* Pattern fails - no * to */
92 		return (0);	/* adjust */
93 	    pat = star;		/* Restart pattern after * */
94 	    *resp++ = *starend;	/* Copy character to result */
95 	    *resp = '\0';	/* null terminate */
96 	    dat = ++starend;	/* Rescan after copied char */
97 	}
98     }
99 }
100 
101 /****************************************************************
102  * position: position 'fil' at the start of the shell command
103  * portion of a shell archive file.
104  * Kim Storm: removed static variables
105  ****************************************************************/
106 
107 int
unshar_position(FILE * fil)108 unshar_position(FILE * fil)
109 {
110     char            buf[BUFSIZ];
111     long            pos;
112 
113     /* Results from star matcher */
114     char            res1[BUFSIZ], res2[BUFSIZ], res3[BUFSIZ], res4[BUFSIZ];
115     char           *result[4];
116 
117     result[0] = res1, result[1] = res2, result[2] = res3, result[3] = res4;
118 
119     /* rewind (fil);  */
120 
121     while (1) {
122 	/* Record position of the start of this line */
123 	pos = ftell(fil);
124 
125 	/* Read next line, fail if no more */
126 	if (fgets(buf, BUFSIZ, fil) == NULL) {
127 	    msg("no shell commands in file");
128 	    return (0);
129 	}
130 	/* Bail out if we see C preprocessor commands or C comments */
131 	if (stlmatch(buf, "#include") || stlmatch(buf, "# include") ||
132 	    stlmatch(buf, "#define") || stlmatch(buf, "# define") ||
133 	    stlmatch(buf, "#ifdef") || stlmatch(buf, "# ifdef") ||
134 	    stlmatch(buf, "#ifndef") || stlmatch(buf, "# ifndef") ||
135 	    stlmatch(buf, "/*")) {
136 	    msg("file looks like raw C code, not a shar file");
137 	    return (0);
138 	}
139 	/* Does this line start with a shell command or comment */
140 	if (stlmatch(buf, "#") ||
141 	    stlmatch(buf, ":") ||
142 	    stlmatch(buf, "echo ") ||
143 	    stlmatch(buf, "sed ") ||
144 	    stlmatch(buf, "cat ")) {
145 	    fseek(fil, pos, 0);
146 	    return (1);
147 	}
148 	/* Does this line say "Cut here" */
149 	if (smatch(buf, "*CUT*HERE*", result) ||
150 	    smatch(buf, "*cut*here*", result) ||
151 	    smatch(buf, "*TEAR*HERE*", result) ||
152 	    smatch(buf, "*tear*here*", result) ||
153 	    smatch(buf, "*CUT*CUT*", result) ||
154 	    smatch(buf, "*cut*cut*", result)) {
155 	    /* Read next line after "cut here", skipping blank lines */
156 	    while (1) {
157 		pos = ftell(fil);
158 
159 		if (fgets(buf, BUFSIZ, fil) == NULL) {
160 		    msg("no shell commands after 'cut'");
161 		    return (0);
162 		}
163 		if (*buf != '\n')
164 		    break;
165 	    }
166 
167 	    /*
168 	     * Win if line starts with a comment character of lower case
169 	     * letter
170 	     */
171 	    if (*buf == '#' ||
172 		*buf == ':' ||
173 		(('a' <= *buf) && ('z' >= *buf))) {
174 		fseek(fil, pos, 0);
175 		return (1);
176 	    }
177 	    /* Cut here message lied to us */
178 	    msg("invalid data after CUT line");
179 	    return (0);
180 	}
181     }
182 }
183