mirror of
git://projects.qi-hardware.com/fped.git
synced 2024-11-22 19:23:44 +02:00
218 lines
3.8 KiB
C
218 lines
3.8 KiB
C
|
/*
|
||
|
* cpp.c - CPP subprocess
|
||
|
*
|
||
|
* Written 2002-2004, 2006, 2008 by Werner Almesberger
|
||
|
* Copyright 2002, 2003 California Institute of Technology
|
||
|
* Copyright 2004, 2006 Werner Almesberger
|
||
|
* Copyright 2008 by OpenMoko, Inc.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <unistd.h>
|
||
|
#include <string.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <signal.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/wait.h>
|
||
|
|
||
|
#include "cpp.h"
|
||
|
|
||
|
|
||
|
const char *cpp_command = CPP;
|
||
|
|
||
|
static pid_t cpp_pid;
|
||
|
static int cpp_argc = 0;
|
||
|
static const char **cpp_argv = NULL;
|
||
|
static int real_stdin = -1;
|
||
|
|
||
|
|
||
|
void add_cpp_arg(const char *arg)
|
||
|
{
|
||
|
if (!cpp_argc)
|
||
|
cpp_argc = 1;
|
||
|
cpp_argv = realloc(cpp_argv,sizeof(const char *)*(cpp_argc+1));
|
||
|
if (!cpp_argv) {
|
||
|
perror("realloc");
|
||
|
exit(1);
|
||
|
}
|
||
|
if (cpp_argc == 1)
|
||
|
cpp_argv[0] = cpp_command;
|
||
|
if (arg) {
|
||
|
arg = strdup(arg);
|
||
|
if (!arg) {
|
||
|
perror("strdup");
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
cpp_argv[cpp_argc++] = arg;
|
||
|
}
|
||
|
|
||
|
|
||
|
void add_cpp_Wp(const char *arg)
|
||
|
{
|
||
|
char *tmp = strdup(arg);
|
||
|
char *curr,*end;
|
||
|
|
||
|
if (!tmp) {
|
||
|
perror("strdup");
|
||
|
exit(1);
|
||
|
}
|
||
|
curr = tmp;
|
||
|
do {
|
||
|
end = strchr(curr,',');
|
||
|
if (end)
|
||
|
*end++ = 0;
|
||
|
add_cpp_arg(curr);
|
||
|
curr = end;
|
||
|
}
|
||
|
while (end);
|
||
|
free(tmp);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void kill_cpp(void)
|
||
|
{
|
||
|
if (cpp_pid)
|
||
|
(void) kill(cpp_pid,SIGTERM);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void run_cpp(const char *name,int fd,int close_fd)
|
||
|
{
|
||
|
char **arg;
|
||
|
int fds[2];
|
||
|
|
||
|
if (pipe(fds) < 0) {
|
||
|
perror("pipe");
|
||
|
exit(1);
|
||
|
}
|
||
|
if (name)
|
||
|
add_cpp_arg(name);
|
||
|
add_cpp_arg(NULL);
|
||
|
cpp_pid = fork();
|
||
|
if (cpp_pid < 0) {
|
||
|
perror("fork");
|
||
|
exit(1);
|
||
|
}
|
||
|
if (!cpp_pid) {
|
||
|
if (close(fds[0]) < 0) {
|
||
|
perror("close");
|
||
|
exit(1);
|
||
|
}
|
||
|
if (close_fd != -1 && close(close_fd) < 0) {
|
||
|
perror("close");
|
||
|
exit(1);
|
||
|
}
|
||
|
if (fd != -1 && dup2(fd,0) < 0) {
|
||
|
perror("dup2");
|
||
|
exit(1);
|
||
|
}
|
||
|
if (dup2(fds[1],1) < 0) {
|
||
|
perror("dup2");
|
||
|
exit(1);
|
||
|
}
|
||
|
if (execvp(cpp_command,(char **) cpp_argv) < 0) {
|
||
|
/* prototype is weird */
|
||
|
perror(cpp_command);
|
||
|
exit(1);
|
||
|
}
|
||
|
/* not reached */
|
||
|
}
|
||
|
if (close(fds[1]) < 0) {
|
||
|
perror("close");
|
||
|
exit(1);
|
||
|
}
|
||
|
real_stdin = dup(0);
|
||
|
if (real_stdin < 0) {
|
||
|
perror("dup");
|
||
|
exit(1);
|
||
|
}
|
||
|
if (fd != -1 && close(fd) < 0) {
|
||
|
perror("close");
|
||
|
exit(1);
|
||
|
}
|
||
|
if (dup2(fds[0],0) < 0) {
|
||
|
perror("dup2");
|
||
|
exit(1);
|
||
|
}
|
||
|
for (arg = (char **) cpp_argv+1; *arg; arg++)
|
||
|
free(*arg);
|
||
|
free(cpp_argv);
|
||
|
cpp_argv = NULL;
|
||
|
cpp_argc = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void run_cpp_on_file(const char *name)
|
||
|
{
|
||
|
run_cpp(name,name ? -1 : 0,-1);
|
||
|
atexit(kill_cpp);
|
||
|
}
|
||
|
|
||
|
|
||
|
void run_cpp_on_string(const char *str)
|
||
|
{
|
||
|
int fds[2];
|
||
|
pid_t pid;
|
||
|
int left,wrote;
|
||
|
|
||
|
if (pipe(fds) < 0) {
|
||
|
perror("pipe");
|
||
|
exit(1);
|
||
|
}
|
||
|
run_cpp(NULL,fds[0],fds[1]);
|
||
|
pid = fork();
|
||
|
if (pid < 0) {
|
||
|
perror("fork");
|
||
|
exit(1);
|
||
|
}
|
||
|
if (!pid) {
|
||
|
for (left = strlen(str); left; left -= wrote) {
|
||
|
wrote = write(fds[1],str,left);
|
||
|
if (wrote < 0)
|
||
|
break; /* die silently */
|
||
|
str += wrote;
|
||
|
}
|
||
|
exit(0);
|
||
|
}
|
||
|
if (close(fds[1]) < 0) {
|
||
|
perror("close");
|
||
|
exit(1);
|
||
|
}
|
||
|
atexit(kill_cpp);
|
||
|
}
|
||
|
|
||
|
|
||
|
void reap_cpp(void)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
cpp_pid = 0;
|
||
|
if (waitpid(cpp_pid,&status,0) < 0) {
|
||
|
perror("waitpid");
|
||
|
exit(1);
|
||
|
}
|
||
|
if (!status) {
|
||
|
if (dup2(real_stdin,0) < 0) {
|
||
|
perror("dup2");
|
||
|
exit(1);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
if (WIFEXITED(status))
|
||
|
exit(WEXITSTATUS(status));
|
||
|
if (WIFSIGNALED(status))
|
||
|
fprintf(stderr,"cpp terminated with signal %d\n",WTERMSIG(status));
|
||
|
else
|
||
|
fprintf(stderr,"cpp terminated with incomprehensible status %d\n",
|
||
|
status);
|
||
|
exit(1);
|
||
|
}
|