/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1994-2011 AT&T * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * Glenn Fowler * * * ***********************************************************************/ #pragma prototyped /* * release -- list recent release changes * * coded for portability */ static char id[] = "\n@(#)$Id: release (AT&T Research) 2000-01-28 $\0\n"; #if _PACKAGE_ast #include #include static const char usage[] = "[-?\n@(#)$Id: release (AT&T Research) 2000-01-28 $\n]" USAGE_LICENSE "[+NAME?release - list recent changes]" "[+DESCRIPTION?\brelease\b lists the changes within the date range specified" " by the \b--from\b and \b--to\b options. The input files are assumed to" " contain date tag lines of the form [\acc\a]]\ayy-mm-dd\a [ \atext\a ]]" " (or \bdate\b(1) default format), where \acc\a is determined by a Y2K" " window year of 69 (we can produce an example coding dated 1991 - this" " can be patented?, how about 1+1=2?.) The date tag lines are followed by" " \areadme\a text in reverse chronological order (newer entries at the" " top of the file.) If no selection options are spcified then all" " changes are listed. If no \afile\a operands are specified then the" " standard input is read.]" "[+?The entries for each \afile\a are annotated with the file directory name.]" "[f:from?Entries older than \adate\a are omitted.]:[date]" "[r:release?List all changes that include the first \acount\a release marks." " A release mark has a date tag followed by optional space and at least" " three \b-\b characters. Changes from release mark \acount\a+1 are not" " listed. If there are no release marks then the date range is used;" " if there is at least one release mark then the date range is ignored" " and at most \acount\a release marks will be listed.]#[count]" "[t:to?Entries newer than \adate\a are omitted.]:[date]" "[V?Print the program version and exit.]" "\n" "\n[ file ... ]\n" "\n" "[+SEE ALSO?\bpackage\b(1)]" ; #else #define elementsof(x) ((int)(sizeof(x)/sizeof(x[0]))) #define NiL ((char*)0) #endif #include #include #include #include #if !_PACKAGE_ast && defined(__STDC__) #include #include #endif static char mon[] = "janfebmaraprmayjunjulaugsepoctnovdec"; static char day[] = "sunmontuewedthufrisat"; #if !_PACKAGE_ast static void usage() { fprintf(stderr, "Usage: release [-V] [-h hi-date] [-l lo-date] [-r count] [ file ...]\n"); exit(2); } #endif static unsigned long number(register char* s, char** e) { unsigned long q = 0; while (isspace(*s)) s++; while (isdigit(*s)) q = q * 10 + *s++ - '0'; if (e) *e = s; return q; } unsigned long string(register char* s, char* tab, int num, int siz, char** e) { register int i; register int j; char buf[16]; while (isspace(*s)) s++; for (i = 0; i < siz; i++) buf[i] = isupper(s[i]) ? tolower(s[i]) : s[i]; for (i = 0; i < num; i += siz) for (j = 0; j < siz && buf[j] == tab[j+i]; j++) if (j == (siz - 1)) { *e = s + siz; return i / siz + 1; } return 0; } static unsigned long date(char* s, char** e) { char* t; unsigned long y; unsigned long m; unsigned long d; if (isdigit(*s)) { y = number(s, &t); if (*t != '-') return 0; switch (t - s) { case 2: y += 1900; if (y <= 1969) y += 100; break; case 4: if (y < 1969) return 0; break; } if (!(m = number(++t, &s))) return 0; if ((s - t) != 2 || *s != '-' || m < 1 || m > 12) return 0; if (!(d = number(++s, &t))) return 0; if ((t - s) != 2 || d < 1 || d > 31) return 0; } else { if (string(s, day, elementsof(day), 3, &t)) s = t; if (!(m = string(s, mon, elementsof(mon), 3, &t))) return 0; if (!(d = number(t, &s))) return 0; for (y = 1969; *s; s++) if ((y = number(s, &t)) && (t - s) == 4) { if (y < 1969) return 0; break; } } if (e) { while (isspace(*t)) t++; *e = t; } return ((y - 1969) * 13 + m) * 32 + d; } int main(int argc, char** argv) { register char* s; register char* u; register char* v; char* p; char* e; int i; unsigned long t; unsigned long lo; unsigned long hi; int mk; FILE* f; char buf[1024]; mk = 0; lo = hi = 0; #if _PACKAGE_ast error_info.id = "release"; for (;;) { switch (optget(argv, usage)) { case 'f': if (!(lo = date(opt_info.arg, &e)) || *e) { error(2, "%s: invalid from date [%s]", opt_info.arg, e); return 1; } continue; case 'r': mk = opt_info.num + 1; continue; case 't': if (!(hi = date(opt_info.arg, &e)) || *e) { error(2, "%s: invalid to date [%s]", opt_info.arg, e); return 1; } continue; case 'V': sfprintf(sfstdout, "%s\n", id + 10); return 0; case '?': error(ERROR_USAGE|4, "%s", opt_info.arg); continue; case ':': error(2, "%s", opt_info.arg); continue; } break; } if (error_info.errors) error(ERROR_USAGE|4, "%s", optusage(NiL)); argv += opt_info.index; #else while ((s = *++argv) && *s == '-' && *(s + 1)) { if (*(s + 1) == '-') { if (!*(s + 2)) { argv++; break; } usage(); break; } for (;;) { switch (i = *++s) { case 0: break; case 'f': case 't': if (!*(v = ++s) && !(v = *++argv)) { s = "??"; continue; } if (!(t = date(v, &e)) || *e) { fprintf(stderr, "release: -%c%s: invalid date [%s]\n", i, s, e); return 1; } switch (i) { case 'f': lo = t; break; case 't': hi = t; break; } break; case 'r': if (!*(v = ++s) && !(v = *++argv)) { s = "??"; continue; } mk = number(v, &e) + 1; if (*e) { fprintf(stderr, "release: -%c%s: invalid count\n", i, s); return 1; } break; case 'V': fprintf(stdout, "%s\n", id + 10); return 0; default: fprintf(stderr, "release: -%c: unknown option\n", i); /*FALLTHROUGH*/ case '?': usage(); break; } break; } } #endif do { if (!(p = *argv++) || !*p || *p == '-' && !*(p + 1)) { argv--; p = ""; f = stdin; } else if (!(f = fopen(p, "r"))) { fprintf(stderr, "release: %s: cannot read", p); return 1; } while (s = fgets(buf, sizeof(buf), f)) { if (t = date(s, &e)) { if (mk && e[0] == '-' && e[1] == '-' && e[2] == '-' && !--mk) break; if (t < lo) break; if (hi && t > hi) continue; if (p) { if (*p) { for (u = v = p; *p; p++) if (*p == '/') { v = u; u = p + 1; } printf("\n:::::::: "); while ((i = *v++) && i != '/') fputc(i, stdout); printf(" ::::::::\n\n"); } p = 0; } } if (!p) fputs(s, stdout); } if (f == stdin) break; fclose(f); } while (*argv); return 0; }