delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2003/02/08/08:12:59

From: "Cyrus Patel" <cyp AT fb14 DOT uni-mainz DOT de>
Organization: Johannes Gutenberg Universitaet
To: djgpp-workers AT delorie DOT com
Date: Sat, 08 Feb 2003 14:08:34 +0100
MIME-Version: 1.0
Subject: Re: fix for copyrite.c[c]/copyrite.pl
Message-ID: <3E450FB4.28479.B954E177@localhost>
In-reply-to: <200302071708.h17H88j18697@greed.delorie.com>
References: <3E439D65 DOT 16225 DOT B3AE5156 AT localhost> (cyp AT fb14 DOT uni-mainz DOT de)
X-mailer: Pegasus Mail for Windows (v4.02a)
Reply-To: djgpp-workers AT delorie DOT com
Errors-To: nobody AT delorie DOT com
X-Mailing-List: djgpp-workers AT delorie DOT com
X-Unsubscribes-To: listserv AT delorie DOT com

--Message-Boundary-27154
Content-type: text/plain; charset=US-ASCII
Content-transfer-encoding: 7BIT
Content-description: Mail message body

On 7 Feb 2003 at 12:08, DJ Delorie wrote:

> You attached the file as type "application/octet-stream" intead of
> "text/plain".  That triggered the virus filter.  Please resubmit it
> (to djgpp-workers AT delorie DOT com) as a plain text attachment.

ah, ok. here goes.




---------------------------------------------
Sign seen outside a Bangkok temple:
  "It is forbidden to enter a woman even a foreigner if dressed as a 
man."



--Message-Boundary-27154
Content-type: Application/Octet-stream; name="COPYRITE.C"; type=Text
Content-disposition: attachment; filename="COPYRITE.C"

/*
 * This utility walks a directory structure looking at all 
 * source/makefiles and pre-pending/updating DJ copyright notices
 * - if the file being checked has no copyright notice at all or
 * - if a machine-generated (see next comment) DJ copyright notice 
 *   is present but is older than the file's last-modified-date.
 *
 * A manually inserted copyright notice, regardless of (C) holder, 
 * will never be modified or subsumed. So, for example this file 
 * will not be prepended with a copyright notice because it already 
 * contains lines that say "Copyright (C) ..."
 *
 * Automatically prepended copyright notices comes in 5 variations:
 * 1) A single line with a single year:
 *     Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
 * 2) A single line with a year list:
 *     Copyright (C) 1995, 1999 DJ Delorie, see COPYING.DJ for details
 * 3) A single line with a hyphenated from-to:
 *     Copyright (C) 1995-2002 DJ Delorie, see COPYING.DJ for details
 * 4) Multi-line:
 *     Copyright (C) 1995, 1996, 1997, 1999, 2000, 2001 DJ Delorie
 *     see COPYING.DJ for details
 * 5) Multiple single lines like 1), each with a different year:
 *    This is the form generated by the old copyright.cc/.pl and 
 *    when updated, will be converted to other forms (2,3,4).
 *   
 * Cyrus Patel <cyp AT fb14 DOT uni-mainz DOT de> wrote this after noticing that
 * the old copyrite.cc did not probe into the file to check for
 * non-DJ copyrights, which was something that the older copyrite.pl 
 * did (that functionality was inadvertantly lost when the .pl 
 * version was ported to .cc). The loss of that functionality caused 
 * Berkeley and IEEE/Open Group copyrights to be subsumed, which was,
 * in his opinion, not an honorable thing to do.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <time.h>
#if defined(__TURBOC__)
#  include <utime.h>
#  include <dirent.h>
#  include <dir.h>
#  include <io.h>
#  ifndef S_ISDIR
#    define S_ISDIR(m)    (((m) & S_IFMT) == S_IFDIR)
#    define S_ISREG(m)    (((m) & S_IFMT) == S_IFREG)
#  endif
#  define sys_nerr    _sys_nerr
#  define sys_errlist _sys_errlist
#elif defined(__WATCOMC__)
#  include <sys/utime.h>
#  include <direct.h>
#  include <unistd.h>
#else
#  include <utime.h>
#  include <dirent.h>
#  include <unistd.h>
#endif

/* 
 * Counters (static so they don't consume stack space).
*/
static struct
{
  unsigned long dirs_scanned;
  unsigned long files_scanned;
  unsigned long files_updated;
} counters;


/*
 * Obtain the 'comment type' for a filename.
 * Arguments: 'fname' is a filename without a path. 
 * Returns '#' for makefiles, 
 *         ';' for .asm, 
 *         '*' for .c/.h/.cc/.cpp/.y/.s/.S
*/
static int get_comment_type(const char *_fname)
{
  char *extn = (char *)0;
  int cmttype;
  char fname[64];
  unsigned int i;

  i = 0;
  while (*_fname && i < (sizeof(fname)-1))
  {
    if ((fname[i++] = (char)tolower(*_fname++)) == '.')
      extn = &fname[i];
  }
  if (*_fname)
  {
    extn = (char *)0;
    i = 0;
  } 
  fname[i] = '\0';

  cmttype = 0;
  if (!extn)
  {
    if (strcmp(fname, "makefile") == 0)
      cmttype = '#';
  }
  else if (strncmp(fname,"makefile.",9) == 0)
  {
    if (strcmp(extn, "def") == 0 || 
        strcmp(extn, "inc") == 0 ||
        strcmp(extn, "prg") == 0 ||
        strcmp(extn, "lib") == 0)
      cmttype = '#';
  }
  else if (strcmp(extn, "h"  ) == 0 ||
           strcmp(extn, "c"  ) == 0 ||
           strcmp(extn, "cc" ) == 0 ||
           strcmp(extn, "cpp") == 0 ||
           strcmp(extn, "c++") == 0 ||
           strcmp(extn, "s"  ) == 0 ||
           strcmp(extn, "y"  ) == 0)
  {
    cmttype = '*';
  }
  else if (strcmp(extn, "asm") == 0)  
  {
    cmttype = ';';
  }

  return cmttype;
}

/* wrapper for getcwd() because
 * not all libcs have a getcwd() that
 * malloc()s the buffer if necessary.
*/
static char *_my_getcwd(void)
{
  char *cwd = (char *)malloc(256);
  if (cwd)
  {
    if (getcwd(cwd, 256))
    {
      unsigned int len = strlen(cwd);
      if (len > 0 && (cwd[len-1] == '/' || cwd[len-1] == '\\'))
        cwd[--len] = '\0';
    }
    else   
    {
      int err = errno;
      free(cwd);
      cwd = (char *)0;
      errno = err;
    }
  }
  return cwd;
}

/* 
 * print an error message.
*/
static void do_fail_msg(const char *msg, const char *fname)
{
  const char *emsg = (const char *)0;
  int err = errno; 
  char *cwd;

  if (err > 0) /* -1 and 0 are special */
    emsg = strerror(err);

  cwd = _my_getcwd();
  fprintf(stderr, "%s/%s: %s%s%s\n", 
                  (cwd?cwd:"???"), (fname?fname:""), msg,
                  (emsg?": ":""), (emsg?emsg:"") );
  if (cwd)
    free(cwd);

  return;
}  

/*
 * Update the copyright notice in a file (if necessary).
 * Arguments: the filename (without path), and the its stat info.
 * Returns: nothing.
 *
 * - If something in the file advises against an edit, do nothing.
 * - If the file contains no copyright notice, prepend a DJ one.
 * - If the file contains a DJ copyright, ensure it is up-to-date.
 * - If the file contains a non-DJ copyright *AND* a DJ copyright
 *   *AND* that DJ copyright was an automatically prepended one, 
 *   then remove the latter - It had been prepended by the old
 *   broken copyright.cc.
*/
static void do_file(const char *fname, struct stat *statblk)
{
  if (statblk->st_size != 0L && 
     ((unsigned long)statblk->st_size) < (UINT_MAX-128))
  {
    int cmttype = get_comment_type(fname);

    if (cmttype)
    {
      size_t filesize = (size_t)statblk->st_size;
      int fd = open(fname, O_RDONLY|O_BINARY);
      char *fbuff = (char *)0;

      if (fd == -1)
      {
        do_fail_msg("Unable to open file", fname);
      }
      else 
      {
        fbuff = (char *)malloc(filesize + 100);
        if (!fbuff)
        {
          do_fail_msg("Unable to alloc fbuf", fname);
        }
        else 
        {
          errno = 0;
          if (filesize != (size_t)read(fd, fbuff, filesize))
          {
            do_fail_msg("Unable to read file", fname );
            free(fbuff);
            fbuff = (char *)0;
          }
        }
        close(fd);
      }

      if (fbuff)
      {
        /* yearlist is the list of (c) years that are strung together */
        /* hyphenates if there are more years than slots available */
        char yearlist[((78-sizeof("(* copyright (c) dj delorie *)"))/6)-1];
        char linebuf[256+((sizeof(yearlist)/sizeof(yearlist[0]))*6)]; 
        int fyear, loyear = 0, hiyear = 0, hyphyear = 0;
        int modified = 0, txtmode = 0, nondj = -1;
        unsigned int lineschkd = 0, numyears = 0;
        size_t pos, offset = 0;
        const char *p;

        while (lineschkd < 25) /* 25 lines == one screenfull */
        {
          pos = 0;
          while (offset < filesize) 
          {
            char c = fbuff[offset++];
            if (c == '\n')
              break;
            if (c == '\r')
            {
              txtmode = 1;
              if (offset < filesize && fbuff[offset] == '\n')
                offset++;
              break;
            } 
            if (pos < (sizeof(linebuf)-1))
              linebuf[pos++] = c;
          }
          linebuf[pos] = '\0';


          if (strstr(linebuf, "DO NO""T EDIT"))
          {
            printf("%s: skipped (saw DO NO""T EDIT)\n", fname );
            modified = 0;
            nondj = 1;
            break;
          }
          else if (!strstr(linebuf, "Copy""right "))
          {
            lineschkd++;
            if (lineschkd == 1 && nondj == 0)
            {
              if (strstr(linebuf, "see COPYING.""DJ for details"))
              {
                /* Pull up continuation of DJ (c) - split over two lines */
                filesize -= offset;
                memmove( &fbuff[0], &fbuff[offset], filesize );
                lineschkd = 0;
                offset = 0;
              }
              else if (cmttype == '*' && pos >= 2)
              {
                /* Pull up "*)" on a line of its own - its part of 
                 * a DJ (c) that was split over three lines.
                */
                while (pos > 0 && 
                     (linebuf[pos-1] == ' ' || linebuf[pos-1] == '\t'))
                  pos--;
                linebuf[pos] = '\0';

                p = &linebuf[0];
                while (*p == ' ' || *p == '\t')
                  p++;
                if (*p == '*' && p[1] == '/' && p[2] == '\0')
                {
                  filesize -= offset;
                  memmove( &fbuff[0], &fbuff[offset], filesize );
                  lineschkd = 0;
                  offset = 0;
                }
              }
            } /* if (lineschkd == 1 && nondj == 0) */
          }  
          else if (lineschkd == 0 && strstr(linebuf," workaround ") &&
                                     strstr(linebuf," prepender"))
          {
            /* no longer using broken copyrite.cc so remove the hack */
            filesize -= offset;
            memmove( &fbuff[0], &fbuff[offset], filesize );
            nondj = modified = 1;
            printf("%s: found broken copyrite.cc workaround\n", fname );
            break;
          }
          else if ((p = strstr(linebuf, " DJ Del""orie")) == ((const char *)0))
          {
            printf("%s: %s\n", fname, linebuf );
            nondj = 1;
            break;
          }
          else if (lineschkd != 0)
          {
            lineschkd++;
          }
          else /* have an auto-prepended dj copyright */
          {              
            while (p > &linebuf[0] && *p != ')')
              p--;
            if (p > &linebuf[0] && *p == ')')
            {
              p++;
              while (*p)
              {
                while (*p == ',' || *p == '-' || *p == ' ')
                {
                  if (*p == '-')
                    hyphyear = 1;
                  p++;
                }
                fyear = atoi(p);
                p += 4;
                if (fyear < 1990 || fyear > 2090)
                  break;
                if (hiyear == 0 || fyear > hiyear)
                  hiyear = fyear;
                if (loyear == 0 || fyear < loyear)
                  loyear = fyear;

                if (numyears == (sizeof(yearlist)/sizeof(yearlist[0])) )
                  hyphyear = 1;
                else if (!hyphyear)
                {
                  fyear -= 1980;
                  pos = 0;
                  while (pos < numyears)
                  {
                    if (yearlist[pos] == fyear)
                      break;
                    if (yearlist[pos] > fyear)
                    {
                      unsigned int pre;
                      for (pre = numyears++; pre > pos; pre--)
                        yearlist[pre] = yearlist[pre-1];
                      yearlist[pos] = (char)fyear;
                      break;
                    }
                    pos++;
                  }
                  if (pos == numyears)
                    yearlist[numyears++] = (char)fyear;
                }

              }
            }
            filesize -= offset;
            memmove( &fbuff[0], &fbuff[offset], filesize );
            modified = 1; /* in case a non-dj copyright is seen later */
            offset = 0;
            nondj = 0;              
          }
        } /* for (lineschkd = 0; lineschkd < 20; lineschkd++) */

        if (nondj <= 0) /* no copyright found, or dj copyright found */
        {
          fyear = localtime(&(statblk->st_mtime))->tm_year;
          if (fyear < 80) 
            fyear += 2000;
          if (fyear < 200) 
            fyear += 1900;        

          modified = 0;
          if (fyear > hiyear) /* always true if no dj copyright */
          {
            offset = 0;
            if (cmttype == '*') 
              linebuf[offset++] = '/';
            linebuf[offset++] = (char)cmttype;
            strcpy( &linebuf[offset], " Copy""right (C)");
            offset = strlen(linebuf);
          
            if (hyphyear)
            {
              linebuf[offset++] = ' ';
              if (loyear < fyear)
                offset += sprintf( &linebuf[offset], "%d-", loyear );
            }
            else
            {
              if (numyears > 0)
                offset += sprintf(&linebuf[offset]," %d", yearlist[0]+1980 );
              for (pos = 1; pos < numyears; pos++)
                offset += sprintf(&linebuf[offset],", %d",yearlist[pos]+1980);
                                                   
              if (numyears > 0)
                linebuf[offset++] = ',';
              linebuf[offset++] = ' ';
            }
            offset += sprintf( &linebuf[offset], "%d ""DJ Del""orie", fyear);

            pos = 0;
            if (offset < (79-sizeof(", see copying.dj for details *)")) )
              linebuf[offset++] = ',';
            else /* put the copying.dj stuff on the next line */
            {
              if (txtmode)
                linebuf[offset++] = '\r';
              linebuf[offset++] = '\n';
              if (cmttype == '*')
                linebuf[offset++] = ' ';
              linebuf[offset++] = (char)cmttype;
              pos = 1;
            } 
            linebuf[offset] = '\0';
            offset = strlen(strcat(linebuf," see COPYING"".DJ for details"));

            if (!pos)
              linebuf[offset++] = ' ';
            else
            {
              if (txtmode)
                linebuf[offset++] = '\r';
              linebuf[offset++] = '\n';
            }
            if (cmttype == '*')
            {
              linebuf[offset++] = '*';
              linebuf[offset++] = '/';
            }  
            if (txtmode)
              linebuf[offset++] = '\r';
            linebuf[offset++] = '\n';

            memmove( &fbuff[offset], &fbuff[0], filesize );
            memcpy( &fbuff[0], &linebuf[0], offset );
            filesize += offset;
            modified = 1;
          }
        }

        if (modified)
        {
          p = "tempxxx.crn";

          fd = open(p, O_RDONLY|O_BINARY);
          if (fd != -1)
          {
            /* don't remove the temp file if we didn't create it. */
            /* it may be the backup from a previous pass. */
            close(fd);
            errno = -1;
            do_fail_msg("Found temp file! May contain source!"
                            "Remove manually if not a backup.", p);
            exit(1);
          }
          else if (rename(fname, p) != 0)
          {
            do_fail_msg("Unable to backup file to tempxxx.crn", fname);
          }
          else
          {
            fd = open(fname, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 
                             statblk->st_mode);
            if (fd == -1)
            {
              do_fail_msg("Unable to open for write", fname);
            }
            else
            {
              errno = 0;
              if (filesize == (size_t)write(fd, fbuff, filesize))
                modified = 0;
              else
                do_fail_msg("Unable to write file", fname);
              close(fd);
            }

            if (modified) /* write failure */
            {
              if (rename(p, fname) != 0)
              {
                do_fail_msg("Unable to restore from backup.\n"
                      "File needs to be renamed/restored manually.",
                      fname );
                exit(1);
              }
            }
            else /* write succeeded */
            {
              struct utimbuf ut;
              ut.actime = statblk->st_atime;
              ut.modtime = statblk->st_mtime;
              utime(fname, &ut);            
              if (nondj <= 0)
                counters.files_updated++;

              fd = open(p, O_RDWR|O_TRUNC|O_BINARY, statblk->st_mode);
              if (fd != -1)
                close(fd);
              rename(p, "rm.me"); /* in case rm fails [path too long] */
              remove("rm.me");  /* (dos fails rm when the path > 64 chars) */
            }
          } /* rename to temp ok */
        } /* if (modified) */

        free(fbuff);

      } /* if (fbuff) */

    } /* if (cmttype != 0) */

  } /* if (filelen ok) */

  counters.files_scanned++;
  return;
}

/*
 * Enumerate all entries in directory.
 * Call do_file() for regular files, or recurse for subdirectories.
*/
static void do_dir(void)
{
  DIR *dp = opendir(".");

  if (!dp)
  {
    do_fail_msg("opendir() failed", 0);
  }
  else
  {
    struct dirent *dep;
    while ((dep = readdir(dp)) != ((struct dirent *)0))
    {
      /* sb is static to preserve stack space */
      static struct stat sb;

      if (dep->d_name[0] == '.')
      {  
        /* skip */;
      }
      else if (stat(dep->d_name, &sb) != 0)
      {
        do_fail_msg("stat() failed", dep->d_name);
      }
      else if (S_ISREG(sb.st_mode))
      {
        do_file(dep->d_name, &sb);
      }
      else if (!S_ISDIR(sb.st_mode))
      {
        /* skip */; 
      }
      else if (chdir(dep->d_name) != 0)
      {
        do_fail_msg("chdir() failed", dep->d_name);
      }
      else  
      {
        do_dir();
        chdir("..");
      }
    }
    closedir(dp);
    counters.dirs_scanned++;
  }

  return;
}

int main(int argc, char *argv[])
{
  memset( &counters, 0, sizeof(counters));

  if (argc < 2)
    do_dir();
  else
  {
    char *cwd = _my_getcwd();
    if (!cwd)
      do_fail_msg("getcwd() failed", 0);
    else 
    {
      if (chdir(argv[1]) != 0)
        fprintf(stderr,"%s: %s\n", argv[1], strerror(errno));
      else
        do_dir();
      chdir(cwd);
      free(cwd);
    }
  }

  printf("Processed %lu file%s (%lu updated) in %lu director%s\n",
          counters.files_scanned, 
          (counters.files_scanned == 1 ? "" : "s"),
          counters.files_updated, 
          counters.dirs_scanned, 
          (counters.dirs_scanned == 1 ? "y" : "ies") );

  return 0;
}

--Message-Boundary-27154--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright 2019   by DJ Delorie     Updated Jul 2019