Files

370 lines
4.8 KiB
C

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#if !__APPLE__
/*
* Appends src to string dst of size dsize (unlike strncat, dsize is the
* full size of dst, not space left). At most dsize-1 characters
* will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
* Returns strlen(src) + MIN(dsize, strlen(initial dst)).
* If retval >= dsize, truncation occurred.
*/
size_t
strlcat(char *dst, const char *src, size_t dsize)
{
const char *odst = dst;
const char *osrc = src;
size_t n = dsize;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end. */
while (n-- != 0 && *dst != '\0')
dst++;
dlen = dst - odst;
n = dsize - dlen;
if (n-- == 0)
return(dlen + strlen(src));
while (*src != '\0') {
if (n != 0) {
*dst++ = *src;
n--;
}
src++;
}
*dst = '\0';
return(dlen + (src - osrc)); /* count does not include NUL */
}
#endif /* !__APPLE__ */
#define MAXSIZE 64000
#define MAXINDENTSIZE 80
#define MAXARGSIZE 20
char *argv0;
int
efgetc(FILE *fp)
{
int c;
c = fgetc(fp);
if (c == EOF &&
ferror(fp) != 0) {
perror(argv0);
exit(1);
}
return c;
}
int
efseek(FILE *fp, long offset, int whence)
{
int s;
s = fseek(fp, offset, whence);
if (s == -1) {
perror(argv0);
exit(1);
}
return s;
}
int
eungetc(int c, FILE *fp)
{
int uc;
uc = ungetc(c, fp);
if (uc == EOF) {
perror(argv0);
exit(1);
}
return uc;
}
size_t
estrlcat(char *dst, const char *src, size_t dstsize)
{
size_t n;
n = strlcat(dst, src, dstsize);
if (n >= dstsize) {
fprintf(stderr, "%s: Buffer overflow\n", argv0);
exit(1);
}
return n;
}
int
eclose(int d)
{
int s;
s = close(d);
if (s == -1) {
perror(argv0);
exit(1);
}
return s;
}
char *
strappend(char *s, char c)
{
size_t len;
len = strlen(s);
s[len] = c;
s[len + 1] = '\0';
return s ;
}
int
shebang(FILE *fp)
{
int c;
c = efgetc(fp);
if (c != '#') {
eungetc(c, fp);
return 0;
}
c = efgetc(fp);
if (c != '!') {
eungetc(c, fp);
eungetc('#', fp);
return 0;
}
c = efgetc(fp);
if (c == '\n') {
eungetc(c, fp);
eungetc('!', fp);
eungetc('#', fp);
return 0;
}
for (;;) {
c = efgetc(fp);
if (c == '\n')
break;
}
return 1;
}
int
token(FILE *fp, int consume)
{
int c;
c = efgetc(fp);
if (c != '#') {
eungetc(c, fp);
return 0;
}
c = efgetc(fp);
if (c != '!') {
eungetc(c, fp);
eungetc('#', fp);
return 0;
};
c = efgetc(fp);
if (c != '\n') {
eungetc(c, fp);
eungetc('!', fp);
eungetc('#', fp);
return 0;
}
if (consume == 0) {
eungetc(c, fp);
eungetc('!', fp);
eungetc('#', fp);
}
return 1;
}
size_t
output(char *s)
{
return estrlcat(s, "echo \"", MAXSIZE);
}
size_t
outputend(char *s)
{
return estrlcat(s, "\"\n", MAXSIZE);
}
int main(int argc, char **argv)
{
char s[MAXSIZE] = "", indent[MAXINDENTSIZE] = "",
*eargv[MAXARGSIZE] = {"sh", "-c", s, "sh", NULL};
FILE *fp;
int size, c, i, fd[2], o = 0, status = 0, d = 0;
argv0 = argv[0];
if (argc == 1) {
fprintf(stderr, "usage: %s file [args ...]\n", argv[0]);
return 1;
}
if (strcmp(argv[1], "-d") == 0) {
if (argc == 2) {
fprintf(stderr, "usage: %s file [args ...]\n", argv[0]);
return 1;
}
d = 1;
fp = fopen(argv[2], "r");
} else {
fp = fopen(argv[1], "r");
}
if (!fp) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], d ? argv[2] : argv[1], strerror(errno));
return 1;
}
efseek (fp, 0, SEEK_END);
size = ftell(fp);
if(size == 0) return 0;
efseek(fp, -1, SEEK_END);
c = efgetc(fp);
if (c != '\n') {
fprintf(stderr, "%s: %s: No newline at end of file\n",
argv[0], d ? argv[2] : argv[1]);
exit(1);
}
efseek(fp, 0, SEEK_SET);
shebang(fp);
if (!token(fp, 1)) {
output(s);
o = 1;
}
for(;;) {
if (token(fp, 1)) {
if (!o) {
c = efgetc(fp);
if (c == EOF)
goto done;
eungetc(c, fp);
output(s);
} else
outputend(s);
o = !o;
}
c = efgetc(fp);
if (c == EOF)
break;
if (c == '\n') {
indent[0] = 0;
c = efgetc(fp);
if (c == EOF)
break;
for (;;) {
if (c != ' ' && c != '\t')
break;
strappend(indent, c);
c = efgetc(fp);
if (c == EOF)
break;
}
eungetc(c, fp);
if (token(fp, 0) && o)
continue;
strappend(s, '\n');
estrlcat(s, indent, MAXSIZE);
continue;
}
strappend(s, c);
}
if (o) {
outputend(s);
o = 0;
}
done:
if(d) {
puts(s);
return 0;
}
if (pipe(fd) == -1) {
perror(argv0);
return 1;
}
switch (fork()) {
case -1:
perror(argv0);
return 1;
case 0:
eclose(fd[1]);
eclose(fd[0]);
for (i = 2; i < argc; i++)
eargv[i+2] = argv[i];
if (execv("/bin/sh", eargv) == -1) {
perror(argv0);
return 1;
}
break;
default:
eclose(fd[1]);
eclose(fd[0]);
if (wait(&status) == -1) {
perror(argv0);
return 1;
}
}
return status;
}