From: "Cyrus Patel" Organization: Johannes Gutenberg Universitaet To: djgpp-workers AT delorie DOT com Date: Sat, 08 Feb 2003 14:08:34 +0100 MIME-Version: 1.0 Content-type: Multipart/Mixed; boundary=Message-Boundary-27154 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 Precedence: bulk --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 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 #include #include #include #include #include #include #include #include #include #if defined(__TURBOC__) # include # include # include # include # 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 # include # include #else # include # include # include #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--