Logo Search packages:      
Sourcecode: pcmciautils version File versions  Download package

ccdv.c

/* ccdv.c
 *
 * Copyright (C) 2002-2003, by Mike Gleason, NcFTP Software.
 * All Rights Reserved.
 *
 * Licensed under the GNU Public License.
 */
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#define SETCOLOR_SUCCESS      (gANSIEscapes ? "\033\1331;32m" : "")
#define SETCOLOR_FAILURE      (gANSIEscapes ? "\033\1331;31m" : "")
#define SETCOLOR_WARNING      (gANSIEscapes ? "\033\1331;33m" : "")
#define SETCOLOR_NORMAL       (gANSIEscapes ? "\033\1330;39m" : "")

#define TEXT_BLOCK_SIZE 8192
#define INDENT 2

#define TERMS "vt100:vt102:vt220:vt320:xterm:xterm-color:ansi:linux:scoterm:scoansi:dtterm:cons25:cygwin"

size_t gNBufUsed = 0, gNBufAllocated = 0;
char *gBuf = NULL;
int gCCPID;
char gAction[200] = "";
char gTarget[200] = "";
char gAr[32] = "";
char gArLibraryTarget[64] = "";
int gDumpCmdArgs = 0;
char gArgsStr[1000];
int gColumns = 80;
int gANSIEscapes = 0;
int gExitStatus = 95;

static void DumpFormattedOutput(void)
{
      char *cp;
      char spaces[8 + 1] = "        ";
      char *saved;
      int curcol;
      int i;

      curcol = 0;
      saved = NULL;
      for (cp = gBuf + ((gDumpCmdArgs == 0) ? strlen(gArgsStr) : 0); ; cp++) {
            if (*cp == '\0') {
                  if (saved != NULL) {
                        cp = saved;
                        saved = NULL;
                  } else break;
            }
            if (*cp == '\r')
                  continue;
            if (*cp == '\t') {
                  saved = cp + 1;
                  cp = spaces + 8 - (8 - ((curcol - INDENT - 1) % 8));
            }
            if (curcol == 0) {
                  for (i = INDENT; --i >= 0; )
                        putchar(' ');
                  curcol = INDENT;
            }
            putchar(*cp);
            if (++curcol == (gColumns - 1)) {
                  putchar('\n');
                  curcol = 0;
            } else if (*cp == '\n')
                  curcol = 0;
      }
      free(gBuf);
}     /* DumpFormattedOutput */



/* Difftime(), only for timeval structures.  */
static void TimeValSubtract(struct timeval *tdiff, struct timeval *t1, struct timeval *t0)
{
      tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
      tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
      if (tdiff->tv_usec < 0) {
            tdiff->tv_sec--;
            tdiff->tv_usec += 1000000;
      }
}     /* TimeValSubtract */



static void Wait(void)
{
      int pid2, status;

      do {
            status = 0;
            pid2 = (int) waitpid(gCCPID, &status, 0);
      } while (((pid2 >= 0) && (! WIFEXITED(status))) || ((pid2 < 0) && (errno == EINTR)));
      if (WIFEXITED(status))
            gExitStatus = WEXITSTATUS(status);
}     /* Wait */



static int SlurpProgress(int fd)
{
      char s1[71];
      char *newbuf;
      int nready;
      size_t ntoread;
      ssize_t nread;
      struct timeval now, tnext, tleft;
      fd_set ss;
      fd_set ss2;
      const char *trail = "/-\\|", *trailcp;

      trailcp = trail;
      snprintf(s1, sizeof(s1), "%s%s%s... ", gAction, gTarget[0] ? " " : "", gTarget);
      printf("\r%-70s%-9s", s1, "");
      fflush(stdout);

      gettimeofday(&now, NULL);
      tnext = now;
      tnext.tv_sec++;
      tleft.tv_sec = 1;
      tleft.tv_usec = 0;
      FD_ZERO(&ss2);
      FD_SET(fd, &ss2);
      for(;;) {
            if (gNBufUsed == (gNBufAllocated - 1)) {
                  if ((newbuf = (char *) realloc(gBuf, gNBufAllocated + TEXT_BLOCK_SIZE)) == NULL) {
                        perror("ccdv: realloc");
                        return (-1);
                  }
                  gNBufAllocated += TEXT_BLOCK_SIZE;
                  gBuf = newbuf;
            }
            for (;;) {
                  ss = ss2;
                  nready = select(fd + 1, &ss, NULL, NULL, &tleft);
                  if (nready == 1)
                        break;
                  if (nready < 0) {
                        if (errno != EINTR) {
                              perror("ccdv: select");
                              return (-1);
                        }
                        continue;
                  }
                  gettimeofday(&now, NULL);
                  if ((now.tv_sec > tnext.tv_sec) || ((now.tv_sec == tnext.tv_sec) && (now.tv_usec >= tnext.tv_usec))) {
                        tnext = now;
                        tnext.tv_sec++;
                        tleft.tv_sec = 1;
                        tleft.tv_usec = 0;
                        printf("\r%-71s%c%-7s", s1, *trailcp, "");
                        fflush(stdout);
                        if (*++trailcp == '\0')
                              trailcp = trail;
                  } else {
                        TimeValSubtract(&tleft, &tnext, &now);
                  }
            }
            ntoread = (gNBufAllocated - gNBufUsed - 1);
            nread = read(fd, gBuf + gNBufUsed, ntoread);
            if (nread < 0) {
                  if (errno == EINTR)
                        continue;
                  perror("ccdv: read");
                  return (-1);
            } else if (nread == 0) {
                  break;
            }
            gNBufUsed += nread;
            gBuf[gNBufUsed] = '\0';
      }
      snprintf(s1, sizeof(s1), "%s%s%s: ", gAction, gTarget[0] ? " " : "", gTarget);
      Wait();
      if (gExitStatus == 0) {
            printf("\r%-70s", s1);
            printf("[%s%s%s]", ((gNBufUsed - strlen(gArgsStr)) < 4) ? SETCOLOR_SUCCESS : SETCOLOR_WARNING, "OK", SETCOLOR_NORMAL);
            printf("%-5s\n", " ");
      } else {
            printf("\r%-70s", s1);
            printf("[%s%s%s]", SETCOLOR_FAILURE, "ERROR", SETCOLOR_NORMAL);
            printf("%-2s\n", " ");
            gDumpCmdArgs = 1; /* print cmd when there are errors */
      }
      fflush(stdout);
      return (0);
}     /* SlurpProgress */



static int SlurpAll(int fd)
{
      char *newbuf;
      size_t ntoread;
      ssize_t nread;

      printf("%s%s%s.\n", gAction, gTarget[0] ? " " : "", gTarget);
      fflush(stdout);

      for(;;) {
            if (gNBufUsed == (gNBufAllocated - 1)) {
                  if ((newbuf = (char *) realloc(gBuf, gNBufAllocated + TEXT_BLOCK_SIZE)) == NULL) {
                        perror("ccdv: realloc");
                        return (-1);
                  }
                  gNBufAllocated += TEXT_BLOCK_SIZE;
                  gBuf = newbuf;
            }
            ntoread = (gNBufAllocated - gNBufUsed - 1);
            nread = read(fd, gBuf + gNBufUsed, ntoread);
            if (nread < 0) {
                  if (errno == EINTR)
                        continue;
                  perror("ccdv: read");
                  return (-1);
            } else if (nread == 0) {
                  break;
            }
            gNBufUsed += nread;
            gBuf[gNBufUsed] = '\0';
      }
      Wait();
      gDumpCmdArgs = (gExitStatus != 0);  /* print cmd when there are errors */
      return (0);
}     /* SlurpAll */



static const char *Basename(const char *path)
{
      const char *cp;
      cp = strrchr(path, '/');
      if (cp == NULL)
            return (path);
      return (cp + 1);
}     /* Basename */



static const char * Extension(const char *path)
{
      const char *cp = path;
      cp = strrchr(path, '.');
      if (cp == NULL)
            return ("");
      // printf("Extension='%s'\n", cp);
      return (cp);
}     /* Extension */



static void Usage(void)
{
      fprintf(stderr, "Usage: ccdv /path/to/cc CFLAGS...\n\n");
      fprintf(stderr, "I wrote this to reduce the deluge Make output to make finding actual problems\n");
      fprintf(stderr, "easier.  It is intended to be invoked from Makefiles, like this.  Instead of:\n\n");
      fprintf(stderr, "\t.c.o:\n");
      fprintf(stderr, "\t\t$(CC) $(CFLAGS) $(DEFS) $(CPPFLAGS) $< -c\n");
      fprintf(stderr, "\nRewrite your rule so it looks like:\n\n");
      fprintf(stderr, "\t.c.o:\n");
      fprintf(stderr, "\t\t@ccdv $(CC) $(CFLAGS) $(DEFS) $(CPPFLAGS) $< -c\n\n");
      fprintf(stderr, "ccdv 1.1.0 is Free under the GNU Public License.  Enjoy!\n");
      fprintf(stderr, "  -- Mike Gleason, NcFTP Software <http://www.ncftp.com>\n");
      exit(96);
}     /* Usage */



int main(int argc, char **argv)
{
      int pipe1[2];
      int devnull;
      char emerg[256];
      int fd;
      int nread;
      int i;
      int cc = 0, pch = 0;
      const char *quote;

      if (argc < 2)
            Usage();

      snprintf(gAction, sizeof(gAction), "Running %s", Basename(argv[1]));
      memset(gArgsStr, 0, sizeof(gArgsStr));
      for (i = 1; i < argc; i++) {
            // printf("argv[%d]='%s'\n", i, argv[i]);
            quote = (strchr(argv[i], ' ') != NULL) ? "\"" : "";
            snprintf(gArgsStr + strlen(gArgsStr), sizeof(gArgsStr) - strlen(gArgsStr), "%s%s%s%s%s", (i == 1) ? "" : " ", quote, argv[i], quote, (i == (argc - 1)) ? "\n" : "");
            if ((strcmp(argv[i], "-o") == 0) && ((i + 1) < argc)) {
                  if (strcasecmp(Extension(argv[i + 1]), ".o") != 0) {
                        strcpy(gAction, "Linking");
                        snprintf(gTarget, sizeof(gTarget), "%s", Basename(argv[i + 1]));
                  }
            } else if (strchr("-+", (int) argv[i][0]) != NULL) {
                  continue;
            } else if (strncasecmp(Extension(argv[i]), ".c", 2) == 0) {
                  cc++;
                  snprintf(gTarget, sizeof(gTarget), "%s", Basename(argv[i]));
                  // printf("gTarget='%s'\n", gTarget);
            } else if ((strncasecmp(Extension(argv[i]), ".h", 2) == 0) && (cc == 0)) {
                  pch++;
                  snprintf(gTarget, sizeof(gTarget), "%s", Basename(argv[i]));
            } else if ((i == 1) && (strcmp(Basename(argv[i]), "ar") == 0)) {
                  snprintf(gAr, sizeof(gAr), "%s", Basename(argv[i]));
            } else if ((gArLibraryTarget[0] == '\0') && (strcasecmp(Extension(argv[i]), ".a") == 0)) {
                  snprintf(gArLibraryTarget, sizeof(gArLibraryTarget), "%s", Basename(argv[i]));
            }
      }
      if ((gAr[0] != '\0') && (gArLibraryTarget[0] != '\0')) {
            strcpy(gAction, "Creating library");
            snprintf(gTarget, sizeof(gTarget), "%s", gArLibraryTarget);
      } else if (pch > 0) {
            strcpy(gAction, "Precompiling");
      } else if (cc > 0) {
            strcpy(gAction, "Compiling");
      }

      if (pipe(pipe1) < 0) {
            perror("ccdv: pipe");
            exit(97);
      }

      (void) close(0);
      devnull = open("/dev/null", O_RDWR, 00666);
      if ((devnull != 0) && (dup2(devnull, 0) == 0))
            close(devnull);

      gCCPID = (int) fork();
      if (gCCPID < 0) {
            (void) close(pipe1[0]);
            (void) close(pipe1[1]);
            perror("ccdv: fork");
            exit(98);
      } else if (gCCPID == 0) {
            /* Child */
            (void) close(pipe1[0]);       /* close read end */
            if (pipe1[1] != 1) {          /* use write end on stdout */
                  (void) dup2(pipe1[1], 1);
                  (void) close(pipe1[1]);
            }
            (void) dup2(1, 2);            /* use write end on stderr */
            execvp(argv[1], argv + 1);
            perror(argv[1]);
            exit(99);
      }

      /* parent */
      (void) close(pipe1[1]);       /* close write end */
      fd = pipe1[0];                /* use read end */

      gColumns = (getenv("COLUMNS") != NULL) ? atoi(getenv("COLUMNS")) : 80;
      gANSIEscapes = (getenv("TERM") != NULL) && (strstr(TERMS, getenv("TERM")) != NULL);
      gBuf = (char *) malloc(TEXT_BLOCK_SIZE);
      if (gBuf == NULL) 
            goto panic;
      gNBufUsed = 0;
      gNBufAllocated = TEXT_BLOCK_SIZE;
      if (strlen(gArgsStr) < (gNBufAllocated - 1)) {
            strcpy(gBuf, gArgsStr);
            gNBufUsed = strlen(gArgsStr);
      }

      if (isatty(1)) {
            if (SlurpProgress(fd) < 0)
                  goto panic;
      } else {
            if (SlurpAll(fd) < 0)
                  goto panic;
      }
      DumpFormattedOutput();
      exit(gExitStatus);

panic:
      gDumpCmdArgs = 1; /* print cmd when there are errors */
      DumpFormattedOutput();
      while ((nread = read(fd, emerg, (size_t) sizeof(emerg))) > 0)
            (void) write(2, emerg, (size_t) nread);
      Wait();
      exit(gExitStatus);
}     /* main */

Generated by  Doxygen 1.6.0   Back to index