Mail Archives: djgpp-workers/2003/02/08/08:12:59
--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 -