This is main.c in view mode; [Download] [Up]
/***************************************************************/ /* */ /* MAIN.C */ /* */ /* Main program loop, as well as miscellaneous conversion */ /* routines, etc. */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992, 1993, 1994 by David F. Skoll. */ /* */ /***************************************************************/ #include "config.h" #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif #ifdef HAVE_MALLOC_H #include <malloc.h> #endif #ifdef HAVE_UNISTD #include <unistd.h> #endif #include <stdio.h> #include <signal.h> #include <string.h> #ifdef HAVE_STDARG #include <stdarg.h> #else #include <varargs.h> #endif #include <ctype.h> #include <time.h> #if defined(__MSDOS__) || defined(__OS2__) #include <dos.h> #else #include <sys/types.h> #ifndef SYSV #include <sys/time.h> #endif #endif /* if defined(__MSDOS__)... */ #include "types.h" #include "protos.h" #include "expr.h" #include "globals.h" #include "err.h" PRIVATE void DoReminders ARGS ((void)); #if defined(NEED_TIMEGM) && !defined(HAVE_MKTIME) PRIVATE long time_cheat ARGS ((int year, int month)); long timegm ARGS((struct tm *tm)); long timelocal ARGS((struct tm *tm)); #endif static char TPushBuffer[TOKSIZE+1]; /* Buffer for pushing back a token. */ static char *TokenPushed = NULL; #ifdef OS2_POPUP #define Putchar(c) {if (AsPopUp) PutcPopUp(c); else putchar(c);} #else #define Putchar(c) putchar(c) #endif /***************************************************************/ /***************************************************************/ /** **/ /** Main Program Loop **/ /** **/ /***************************************************************/ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int main(int argc, char *argv[]) #else int main(argc, argv) int argc; char *argv[]; #endif { #ifdef HAVE_QUEUED int pid; #endif /* The very first thing to do is to set up ErrFp to be stderr */ ErrFp = stderr; /* Set up global vars */ ArgC = argc; ArgV = argv; InitRemind(argc, argv); if(DoCalendar || DoSimpleCalendar) { ProduceCalendar(); return 0; } /* Not doing a calendar. Do the regular remind loop */ ShouldCache = (Iterations > 1); while (Iterations--) { DoReminders(); if (DebugFlag & DB_DUMP_VARS) { DumpVarTable(); DumpSysVarByName(NULL); } if (!Hush) { if (DestroyOmitContexts()) Eprint("%s", ErrMsg[E_PUSH_NOPOP]); #ifdef HAVE_QUEUED if (!Daemon && !NextMode && !NumTriggered && !NumQueued) printf("%s\n", ErrMsg[E_NOREMINDERS]); else if (!Daemon && !NextMode && !NumTriggered) printf(ErrMsg[M_QUEUED], NumQueued); #else if (!NextMode && !NumTriggered) printf("%s\n", ErrMsg[E_NOREMINDERS]); #endif } /* If it's MS-DOS, reset the file access date. */ /* Note that OS/2 and DOS bound programs have __MSDOS__ */ /* defined, so this test should probably be modified. */ #if defined(__MSDOS__) if (!UseStdin && (RealToday == JulianToday)) SetAccessDate(InitialFile, RealToday); #endif /* If there are sorted reminders, handle them */ if (SortByDate) IssueSortedReminders(); /* If there are any background reminders queued up, handle them */ #ifdef HAVE_QUEUED if (NumQueued || Daemon) { if (DontFork) { HandleQueuedReminders(); return 0; } else { pid = fork(); if (pid == 0) { HandleQueuedReminders(); return 0; } if (pid == -1) { fprintf(ErrFp, "%s", ErrMsg[E_CANTFORK]); return 1; } } } #endif if (Iterations) { ClearGlobalOmits(); DestroyOmitContexts(); DestroyVars(0); NumTriggered = 0; JulianToday++; } } return 0; } /***************************************************************/ /* */ /* DoReminders */ /* */ /* The normal case - we're not doing a calendar. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PRIVATE void DoReminders(void) #else static void DoReminders() #endif { int r; Token tok; char *s; Parser p; if (!UseStdin) FileAccessDate = GetAccessDate(InitialFile); else FileAccessDate = JulianToday; if (FileAccessDate < 0) { fprintf(ErrFp, "%s: '%s'.\n", ErrMsg[E_CANTACCESS], InitialFile); exit(1); } r=OpenFile(InitialFile); if (r) { fprintf(ErrFp, "%s %s: %s\n", ErrMsg[E_ERR_READING], InitialFile, ErrMsg[r]); exit(1); } while(1) { r = ReadLine(); if (r == E_EOF) return; if (r) { Eprint("%s: %s", ErrMsg[E_ERR_READING], ErrMsg[r]); exit(1); } s = FindInitialToken(&tok, CurLine); /* Should we ignore it? */ if (NumIfs && tok.type != T_If && tok.type != T_Else && tok.type != T_EndIf && tok.type != T_IfTrig && ShouldIgnoreLine()) { /*** IGNORE THE LINE ***/ } else { /* Create a parser to parse the line */ CreateParser(s, &p); switch(tok.type) { case T_Empty: case T_Comment: break; case T_Rem: r=DoRem(&p); break; case T_ErrMsg: r=DoErrMsg(&p); break; case T_If: r=DoIf(&p); break; case T_IfTrig: r=DoIfTrig(&p); break; case T_Else: r=DoElse(&p); break; case T_EndIf: r=DoEndif(&p); break; case T_Include: r=DoInclude(&p); break; case T_Exit: DoExit(&p); break; case T_Flush: r=DoFlush(&p); break; case T_Set: r=DoSet(&p); break; case T_Fset: r=DoFset(&p); break; case T_UnSet: r=DoUnset(&p); break; case T_Clr: r=DoClear(&p); break; case T_Debug: r=DoDebug(&p); break; case T_Dumpvars: r=DoDump(&p); break; case T_Banner: r=DoBanner(&p); break; case T_Omit: r=DoOmit(&p); if (r == E_PARSE_AS_REM) { DestroyParser(&p); CreateParser(s, &p); r=DoRem(&p); } break; case T_Pop: r=PopOmitContext(&p); break; case T_Preserve: r=DoPreserve(&p); break; case T_Push: r=PushOmitContext(&p); break; case T_RemType: if (tok.val == RUN_TYPE) { r=DoRun(&p); break; } else { CreateParser(CurLine, &p); r=DoRem(&p); break; } /* If we don't recognize the command, do a REM by default */ /* Note: Since the parser hasn't been used yet, we don't */ /* need to destroy it here. */ default: CreateParser(CurLine, &p); r=DoRem(&p); break; } if (r && (!Hush || r != E_RUN_DISABLED)) Eprint("%s", ErrMsg[r]); /* Destroy the parser - free up resources it may be tying up */ DestroyParser(&p); } } } /***************************************************************/ /* */ /* Julian */ /* */ /* Given day, month, year, return Julian date in days since */ /* 1 January 1990. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int Julian(int year, int month, int day) #else int Julian(year, month, day) int day, month, year; #endif { int y1 = BASE-1, y2 = year-1; int y4 = (y2 / 4) - (y1 / 4); /* Correct for leap years */ int y100 = (y2 / 100) - (y1 / 100); /* Don't count multiples of 100... */ int y400 = (y2 / 400) - (y1 / 400); /* ... but do count multiples of 400 */ return 365 * (year-BASE) + y4 - y100 + y400 + MonthIndex[IsLeapYear(year)][month] + day - 1; } /***************************************************************/ /* */ /* FromJulian */ /* */ /* Convert a Julian date to year, month, day. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC void FromJulian(int jul, int *y, int *m, int *d) #else void FromJulian(jul, y, m, d) int jul; int *y, *m, *d; #endif { int try_yr = (jul / 365) + BASE; int try_mon = 0; int t; /* Inline code for speed... */ int y1 = BASE-1, y2 = try_yr-1; int y4 = (y2 / 4) - (y1 / 4); /* Correct for leap years */ int y100 = (y2 / 100) - (y1 / 100); /* Don't count multiples of 100... */ int y400 = (y2 / 400) - (y1 / 400); /* ... but do count multiples of 400 */ int try_jul= 365 * (try_yr-BASE) + y4 - y100 + y400; while (try_jul > jul) { try_yr--; try_jul -= DaysInYear(try_yr); } jul -= try_jul; t = DaysInMonth(try_mon, try_yr); while (jul >= t) { jul -= t; try_mon++; t = DaysInMonth(try_mon, try_yr); } *y = try_yr; *m = try_mon; *d = jul + 1; return; } /***************************************************************/ /* */ /* ParseChar */ /* */ /* Parse a character from a parse pointer. If peek is non- */ /* zero, then just peek ahead; don't advance pointer. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int ParseChar(ParsePtr p, int *err, int peek) #else int ParseChar(p, err, peek) ParsePtr p; int *err; int peek; #endif { Value val; int r; *err = 0; if (TokenPushed && *TokenPushed) if (peek) return *TokenPushed; else return *TokenPushed++; while(1) { if (p->isnested) { if (*(p->epos)) if (peek) return *(p->epos); else return *(p->epos++); free(p->etext); /* End of substituted expression */ p->etext = NULL; p->epos = NULL; p->isnested = 0; } if (!*(p->pos)) { return 0; } if (*p->pos != BEG_OF_EXPR || !p->allownested) if (peek) return *(p->pos); else return *(p->pos++); p->pos++; r = EvalExpr(&(p->pos), &val); if (r) { *err = r; DestroyParser(p); return 0; } if (*p->pos != END_OF_EXPR) { *err = E_MISS_END; DestroyParser(p); DestroyValue(val); return 0; } p->pos++; r = DoCoerce(STR_TYPE, &val); if (r) { *err = r; return 0; } p->etext = val.v.str; val.type = ERR_TYPE; /* So it's not accidentally destroyed! */ p->isnested = 1; p->epos = p->etext; } } /***************************************************************/ /* */ /* ParseNonSpaceChar */ /* */ /* Parse the next non-space character. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int ParseNonSpaceChar(ParsePtr p, int *err, int peek) #else int ParseNonSpaceChar(p, err, peek) ParsePtr p; int *err; int peek; #endif { int ch; ch = ParseChar(p, err, 1); if (*err) return 0; while (isspace(ch)) { ParseChar(p, err, 0); /* Guaranteed to work */ ch = ParseChar(p, err, 1); if (*err) return 0; } if (!peek) ch = ParseChar(p, err, 0); /* Guaranteed to work */ return ch; } /***************************************************************/ /* */ /* ParseToken */ /* */ /* Parse a token delimited by whitespace. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int ParseToken(ParsePtr p, char *out) #else int ParseToken(p, out) ParsePtr p; char *out; #endif { int c, err; int len = 0; *out = 0; c = ParseChar(p, &err, 0); if (err) return err; while (c && isspace(c)) { c = ParseChar(p, &err, 0); if (err) return err; } if (!c) return OK; *out++ = c; len++; while (c && !isspace(c)) { c = ParseChar(p, &err, 0); if (err) return err; if (len < TOKSIZE && c && !isspace(c)) { *out++ = c; len++; } } *out = 0; return OK; } /***************************************************************/ /* */ /* ParseIdentifier */ /* */ /* Parse a valid identifier - ie, alpha or underscore */ /* followed by alphanum. Return E_BAD_ID if identifier is */ /* invalid. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int ParseIdentifier(ParsePtr p, char *out) #else int ParseIdentifier(p, out) ParsePtr p; char *out; #endif { int c, err; int len = 0; *out = 0; c = ParseChar(p, &err, 0); if (err) return err; while (c && isspace(c)) { c = ParseChar(p, &err, 0); if (err) return err; } if (!c) return E_EOLN; if (c != '$' && c != '_' && !isalpha(c)) return E_BAD_ID; *out++ = c; *out = 0; len++; while (1) { c = ParseChar(p, &err, 1); if (err) return err; if (c != '_' && !isalnum(c)) return OK; if (len < TOKSIZE) { c = ParseChar(p, &err, 0); /* Guaranteed to work */ *out++ = c; *out = 0; len++; } } } /***************************************************************/ /* */ /* EvaluateExpr */ /* */ /* We are expecting an expression here. Evaluate it and */ /* return the value. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int EvaluateExpr(ParsePtr p, Value *v) #else int EvaluateExpr(p, v) ParsePtr p; Value *v; #endif { int bracketed = 0; int r; if (p->isnested) return E_PARSE_ERR; /* Can't nest expressions */ while (isspace(*p->pos)) (p->pos)++; if (!p->pos) return E_PARSE_ERR; /* Missing expression */ if (*p->pos == BEG_OF_EXPR) { (p->pos)++; bracketed = 1; } r = EvalExpr(&(p->pos), v); if (r) return r; if (bracketed) { if (*p->pos != END_OF_EXPR) return E_MISS_END; (p->pos)++; } return OK; } /***************************************************************/ /* */ /* Eprint - print an error message. */ /* */ /***************************************************************/ #ifdef HAVE_STDARG #ifdef HAVE_PROTOS PUBLIC void Eprint(const char *fmt, ...) #else void Eprint(fmt) char *fmt; #endif #else /*VARARGS0*/ void Eprint(va_alist) va_dcl #endif { va_list argptr; #ifndef HAVE_STDARG char *fmt; #endif /* Check if more than one error msg. from this line */ if (!FreshLine && !ShowAllErrors) return; if (FreshLine) { FreshLine = 0; if (strcmp(FileName, "-")) (void) fprintf(ErrFp, "%s(%d): ", FileName, LineNo); else (void) fprintf(ErrFp, "-stdin-(%d): ", LineNo); if (DebugFlag & DB_PRTLINE) OutputLine(ErrFp); } else fprintf(ErrFp, " "); #ifdef HAVE_STDARG va_start(argptr, fmt); #else va_start(argptr); fmt = va_arg(argptr, char *); #endif (void) vfprintf(ErrFp, fmt, argptr); (void) fputc('\n', ErrFp); #ifndef HAVE_STDARG va_end(argptr); #endif return; } /***************************************************************/ /* */ /* OutputLine */ /* */ /* Output a line from memory buffer to a file pointer. This */ /* simply involves escaping newlines. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC void OutputLine(FILE *fp) #else void OutputLine(fp) FILE *fp; #endif { register char *s = CurLine; register char c = 0; while (*s) { if (*s == '\n') putc('\\', fp); putc(*s, fp); c = *s++; } if (c != '\n') putc('\n', fp); } /***************************************************************/ /* */ /* CreateParser */ /* */ /* Create a parser given a string buffer */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC void CreateParser(char *s, ParsePtr p) #else void CreateParser(s, p) char *s; ParsePtr p; #endif { p->text = s; p->pos = s; p->isnested = 0; p->epos = NULL; p->etext = NULL; p->allownested = 1; TokenPushed = NULL; } /***************************************************************/ /* */ /* DestroyParser */ /* */ /* Destroy a parser, freeing up resources used. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC void DestroyParser(ParsePtr p) #else void DestroyParser(p) ParsePtr p; #endif { if (p->isnested && p->etext) { free(p->etext); p->etext = NULL; p->isnested = 0; } } /***************************************************************/ /* */ /* PushToken - one level of token pushback. This is */ /* GLOBAL, not on a per-parser basis. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC void PushToken(const char *tok) #else void PushToken(tok) char *tok; #endif { TokenPushed = TPushBuffer; strcpy(TPushBuffer, tok); strcat(TPushBuffer, " "); /* Separate the pushed token from the next token */ } /***************************************************************/ /* */ /* SystemTime */ /* */ /* Return the system time in seconds past midnight */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC long SystemTime(int realtime) #else long SystemTime(realtime) int realtime; #endif { #if defined( __MSDOS__ ) && defined( __TURBOC__ ) /* Get time in Turbo C */ struct time t; /* If time was supplied on command line, return it. */ if (!realtime && (SysTime != -1L)) return SysTime; gettime(&t); return (long) t.ti_hour * 3600L + (long) t.ti_min * 60L + (long) t.ti_sec; #else /* Get time in Unix or with MSC */ time_t tloc; struct tm *t; if (!realtime && (SysTime != -1L)) return SysTime; (void) time(&tloc); t = localtime(&tloc); return (long) t->tm_hour * 3600L + (long) t->tm_min * 60L + (long) t->tm_sec; #endif } /***************************************************************/ /* */ /* SystemDate */ /* */ /* Obtains today's date. Returns Julian date or -1 for */ /* failure. (Failure happens if sys date is before BASE */ /* year.) */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int SystemDate(int *y, int *m, int *d) #else int SystemDate(y, m, d) int *d; int *m; int *y; #endif { #if defined( __MSDOS__ ) && defined( __TURBOC__ ) /* Get today's date in Turbo C */ struct date da; getdate(&da); *y = da.da_year; *m = da.da_mon - 1; *d = da.da_day; #else /* Get today's date in UNIX or with MSC */ time_t tloc; struct tm *t; (void) time(&tloc); t = localtime(&tloc); *d = t->tm_mday; *m = t->tm_mon; *y = t->tm_year + 1900; #endif return Julian(*y, *m, *d); } /***************************************************************/ /* */ /* DoIf - handle the IF command. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int DoIf(ParsePtr p) #else int DoIf(p) ParsePtr p; #endif { Value v; int r; unsigned syndrome; if (NumIfs >= IF_NEST) return E_NESTED_IF; if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE; else { if ( (r = EvaluateExpr(p, &v)) ) { syndrome = IF_TRUE | BEFORE_ELSE; Eprint("%s", ErrMsg[r]); } else if ( (v.type != STR_TYPE && v.v.val) || (v.type == STR_TYPE && strcmp(v.v.str, "")) ) syndrome = IF_TRUE | BEFORE_ELSE; else syndrome = IF_FALSE | BEFORE_ELSE; } NumIfs++; IfFlags &= ~(IF_MASK << (2*NumIfs - 2)); IfFlags |= syndrome << (2 * NumIfs - 2); if (ShouldIgnoreLine()) return OK; return VerifyEoln(p); } /***************************************************************/ /* */ /* DoElse - handle the ELSE command. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int DoElse(ParsePtr p) #else int DoElse(p) ParsePtr p; #endif { unsigned syndrome; if (!NumIfs) return E_ELSE_NO_IF; syndrome = IfFlags >> (2 * NumIfs - 2); if ((syndrome & IF_ELSE_MASK) == AFTER_ELSE) return E_ELSE_NO_IF; IfFlags |= AFTER_ELSE << (2 * NumIfs - 2); return VerifyEoln(p); } /***************************************************************/ /* */ /* DoEndif - handle the Endif command. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int DoEndif(ParsePtr p) #else int DoEndif(p) ParsePtr p; #endif { if (!NumIfs) return E_ENDIF_NO_IF; NumIfs--; return VerifyEoln(p); } /***************************************************************/ /* */ /* DoIfTrig */ /* */ /* Handle the IFTRIG command. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int DoIfTrig(ParsePtr p) #else int DoIfTrig(p) ParsePtr p; #endif { int r; unsigned syndrome; Trigger trig; TimeTrig tim; int jul; if (NumIfs >= IF_NEST) return E_NESTED_IF; if (ShouldIgnoreLine()) syndrome = IF_TRUE | BEFORE_ELSE; else { if ( (r=ParseRem(p, &trig, &tim)) ) return r; if (trig.typ != NO_TYPE) return E_PARSE_ERR; jul = ComputeTrigger(trig.scanfrom, &trig, &r); if (r) syndrome = IF_TRUE | BEFORE_ELSE; else { if (ShouldTriggerReminder(&trig, &tim, jul)) syndrome = IF_TRUE | BEFORE_ELSE; else syndrome = IF_FALSE | BEFORE_ELSE; } } NumIfs++; IfFlags &= ~(IF_MASK << (2*NumIfs - 2)); IfFlags |= syndrome << (2 * NumIfs - 2); return OK; } /***************************************************************/ /* */ /* ShouldIgnoreLine - given the current state of the IF */ /* stack, should we ignore the current line? */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int ShouldIgnoreLine(void) #else int ShouldIgnoreLine() #endif { register int i, syndrome; /* Algorithm - go from outer to inner, and if any should be ignored, then ignore the whole. */ for (i=0; i<NumIfs; i++) { syndrome = (IfFlags >> (i*2)) & IF_MASK; if (syndrome == IF_TRUE+AFTER_ELSE || syndrome == IF_FALSE+BEFORE_ELSE) return 1; } return 0; } /***************************************************************/ /* */ /* VerifyEoln */ /* */ /* Verify that current line contains no more tokens. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int VerifyEoln(ParsePtr p) #else int VerifyEoln(p) ParsePtr p; #endif { int r; if ( (r = ParseToken(p, TokBuffer)) ) return r; if (*TokBuffer && (*TokBuffer != '#') && (*TokBuffer != ';')) { Eprint("%s: '%s'", ErrMsg[E_EXPECTING_EOL], TokBuffer); return E_EXTRANEOUS_TOKEN; } return OK; } /***************************************************************/ /* */ /* DoDebug */ /* */ /* Set the debug options under program control. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int DoDebug(ParsePtr p) #else int DoDebug(p) ParsePtr p; #endif { int err; int ch; int val=1; while(1) { ch = ParseChar(p, &err, 0); if (err) return err; switch(ch) { case '#': case ';': case 0: return OK; case ' ': case '\t': break; case '+': val = 1; break; case '-': val = 0; break; case 'e': case 'E': if (val) DebugFlag |= DB_ECHO_LINE; else DebugFlag &= ~DB_ECHO_LINE; break; case 'x': case 'X': if (val) DebugFlag |= DB_PRTEXPR; else DebugFlag &= ~DB_PRTEXPR; break; case 't': case 'T': if (val) DebugFlag |= DB_PRTTRIG; else DebugFlag &= ~DB_PRTTRIG; break; case 'v': case 'V': if (val) DebugFlag |= DB_DUMP_VARS; else DebugFlag &= ~DB_DUMP_VARS; break; case 'l': case 'L': if (val) DebugFlag |= DB_PRTLINE; else DebugFlag &= ~DB_PRTLINE; break; } } } /***************************************************************/ /* */ /* DoBanner */ /* */ /* Set the banner to be printed just before the first */ /* reminder is issued. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int DoBanner(ParsePtr p) #else int DoBanner(p) ParsePtr p; #endif { int err; int c; char buf[LINELEN]; /* So we don't mess up the banner if an error occurs */ char *s; c = ParseChar(p, &err, 0); if (err) return err; while (isspace(c)) { c = ParseChar(p, &err, 0); if (err) return err; } if (!c) return E_EOLN; s = buf; while(c) { *s++ = c; c = ParseChar(p, &err, 0); if (err) return err; } *s++ = 0; strcpy(Banner, buf); return OK; } /***************************************************************/ /* */ /* DoRun */ /* */ /* Enable or disable the RUN command under program control */ /* */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int DoRun(ParsePtr p) #else int DoRun(p) ParsePtr p; #endif { int r; if ( (r=ParseToken(p, TokBuffer)) ) return r; /* Only allow RUN ON in top-level script */ if (! StrCmpi(TokBuffer, "ON")) { if (TopLevel()) RunDisabled &= ~RUN_SCRIPT; } /* But allow RUN OFF anywhere */ else if (! StrCmpi(TokBuffer, "OFF")) RunDisabled |= RUN_SCRIPT; else return E_PARSE_ERR; return VerifyEoln(p); } /***************************************************************/ /* */ /* DoFlush */ /* */ /* Flush stdout and stderr */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int DoFlush(ParsePtr p) #else int DoFlush(p) ParsePtr p; #endif { fflush(stdout); fflush(stderr); return VerifyEoln(p); } /***************************************************************/ /* */ /* DoExit */ /* */ /* Handle the EXIT command. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC void DoExit(ParsePtr p) #else void DoExit(p) ParsePtr p; #endif { int r; Value v; r = EvaluateExpr(p, &v); if (r || v.type != INT_TYPE) exit(99); exit(v.v.val); } /***************************************************************/ /* */ /* DoErrMsg */ /* */ /* Issue an error message under program control. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC int DoErrMsg(ParsePtr p) #else int DoErrMsg(p) ParsePtr p; #endif { TimeTrig tt; Trigger t; int r; char *s; t.typ = MSG_TYPE; tt.ttime = SystemTime(0) / 60; if ( (r=DoSubst(p, SubstBuffer, &t, &tt, JulianToday, NORMAL_MODE)) ) return r; s = SubstBuffer; while (isspace(*s)) s++; fprintf(ErrFp, "%s\n", s); return OK; } /***************************************************************/ /* */ /* CalcMinsFromUTC */ /* */ /* Attempt to calculate the minutes from UTC for a specific */ /* date. */ /* */ /***************************************************************/ /* The array FoldArray[2][7] contains sample years which begin on the specified weekday. For example, FoldArray[0][2] is a non-leapyear beginning on Wednesday, and FoldArray[1][5] is a leapyear beginning on Saturday. Used to fold back dates which are too high for the standard Unix representation. NOTE: This implies that you cannot set BASE > 2001!!!!! */ static int FoldArray[2][7] = { {2001, 2002, 2003, 2009, 2010, 2005, 2006}, {2024, 2008, 2020, 2004, 2016, 2000, 2012} }; #ifdef HAVE_PROTOS PUBLIC int CalcMinsFromUTC(int jul, int tim, int *mins, int *isdst) #else int CalcMinsFromUTC(jul, tim, mins, isdst) int jul, tim, *mins, *isdst; #endif { /* Convert jul and tim to an Unix tm struct */ int yr, mon, day; struct tm local, utc, *temp; time_t loc_t, utc_t; FromJulian(jul, &yr, &mon, &day); /* If the year is greater than 2037, some Unix machines have problems. Fold it back to a "similar" year and trust that the UTC calculations are still valid... */ if (FoldYear && yr>2037) { jul = Julian(yr, 0, 1); yr = FoldArray[IsLeapYear(yr)][jul%7]; } local.tm_sec = 0; local.tm_min = tim % 60; local.tm_hour = tim / 60; local.tm_mday = day; local.tm_mon = mon; local.tm_year = yr-1900; local.tm_isdst = -1; /* We don't know whether or not dst is in effect */ #if !defined(HAVE_MKTIME) loc_t = timelocal(&local); local.tm_isdst = 0; utc_t = timegm(&local); #else loc_t = mktime(&local); if (loc_t == -1) return 1; temp = gmtime(&loc_t); utc = *temp; utc.tm_isdst = 0; utc_t = mktime(&utc); if (utc_t == -1) return 1; #endif temp = localtime(&loc_t); #ifdef HAVE_MKTIME if (mins) *mins = (int) ( ((temp->tm_isdst) ? 60 : 0) + (loc_t - utc_t) / 60 ); /* Should use difftime */ #else if (mins) *mins = (int) ((utc_t - loc_t) / 60); #endif if (isdst) *isdst = temp->tm_isdst; return 0; } /***************************************************************/ /* */ /* FillParagraph */ /* */ /* Write a string to standard output, formatting it as a */ /* paragraph according to the FirstIndent, FormWidth and */ /* SubsIndent variables. Spaces are gobbled. Double-spaces */ /* are inserted after '.', '?' and '!'. Newlines in the */ /* source are treated as paragraph breaks. */ /* */ /***************************************************************/ /* A macro safe ONLY if used with arg with no side effects! */ #define ISBLANK(c) (isspace(c) && (c) != '\n') #ifdef HAVE_PROTOS #ifdef OS2_POPUP PUBLIC void FillParagraph(char *s, int AsPopUp) #else PUBLIC void FillParagraph(char *s) #endif #else #ifdef OS2_POPUP void FillParagraph(s, AsPopUp) char *s; int AsPopUp; #else void FillParagraph(s) char *s; #endif #endif { int line = 0; int i, j; int doublespace = 1; int pendspace; int len; char *t; int roomleft; if (!s || !*s) return; /* Skip leading spaces */ while(ISBLANK(*s)) s++; /* Start formatting */ while(1) { /* If it's a carriage return, output it and start new paragraph */ if (*s == '\n') { Putchar('\n'); s++; line = 0; while(ISBLANK(*s)) s++; continue; } if (!*s) { return; } /* Over here, we're at the beginning of a line. Emit the correct number of spaces */ j = line ? SubsIndent : FirstIndent; for (i=0; i<j; i++) { Putchar(' '); } /* Calculate the amount of room left on this line */ roomleft = FormWidth - j; pendspace = 0; /* Emit words until the next one won't fit */ while(1) { while(ISBLANK(*s)) s++; if (*s == '\n') break; t = s; while(*s && !isspace(*s)) s++; len = s - t; if (!len) { return; } if (!pendspace || len+pendspace <= roomleft) { for (i=0; i<pendspace; i++) { Putchar(' '); } while(t < s) { Putchar(*t); if (strchr(EndSent, *t)) doublespace = 2; else if (!strchr(EndSentIg, *t)) doublespace = 1; t++; } } else { s = t; Putchar('\n'); line++; break; } roomleft -= len+doublespace; pendspace = doublespace; } } } #if defined(NEED_TIMEGM) && !defined(HAVE_MKTIME) #define TGM_SEC (1) #define TGM_MIN (60 * TGM_SEC) #define TGM_HR (60 * TGM_MIN) #define TGM_DAY (24 * TGM_HR) #ifdef HAVE_PROTOS PRIVATE long time_cheat(int year, int month) #else static long time_cheat (year, month) int year; int month; #endif { long guess = time((long *) NULL); struct tm g; int diff; g = *gmtime (&guess); while ((diff = year - g.tm_year) > 0) { guess += diff * (363 - TGM_DAY); g = *gmtime (&guess); } g.tm_mday--; guess -= g.tm_sec * TGM_SEC + g.tm_min * TGM_MIN + g.tm_hour * TGM_HR + g.tm_mday * TGM_DAY; return (guess); } #ifdef HAVE_PROTOS PUBLIC long timegm (struct tm *tm) #else long timegm(tm) struct tm *tm; #endif { long clock = time_cheat (tm->tm_year, tm->tm_mon); return (clock + tm->tm_sec * TGM_SEC + tm->tm_min * TGM_MIN + tm->tm_hour * TGM_HR + (tm->tm_mday - 1) * TGM_DAY); } #ifdef HAVE_PROTOS PUBLIC long timelocal (struct tm *tm) #else long timelocal (tm) struct tm *tm; #endif { long zero = 0; struct tm epoch; int tzmin; long clock; struct tm test; epoch = *localtime (&zero); tzmin = epoch.tm_hour * 60 + epoch.tm_min; if (tzmin > 0) { tzmin = 24 * 60 - tzmin; if (epoch.tm_year == 70) tzmin -= 24 * 60; } clock = timegm (tm) + tzmin * TGM_MIN; test = *localtime (&clock); if (test.tm_hour != tm->tm_hour) clock -= TGM_HR; return (clock); } #endif /* NEED_TIMEGM */ /***************************************************************/ /* */ /* LocalToUTC */ /* */ /* Convert a local date/time to a UTC date/time. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC void LocalToUTC(int locdate, int loctime, int *utcdate, int *utctime) #else void LocalToUTC(locdate, loctime, utcdate, utctime) int locdate, loctime, *utcdate, *utctime; #endif { int diff; int dummy; if (!CalculateUTC || CalcMinsFromUTC(locdate, loctime, &diff, &dummy)) diff=MinsFromUTC; loctime -= diff; if (loctime < 0) { loctime += 1440; locdate--; } else if (loctime >= 1440) { loctime -= 1440; locdate++; } *utcdate = locdate; *utctime = loctime; } /***************************************************************/ /* */ /* UTCToLocal */ /* */ /* Convert a UTC date/time to a local date/time. */ /* */ /***************************************************************/ #ifdef HAVE_PROTOS PUBLIC void UTCToLocal(int utcdate, int utctime, int *locdate, int *loctime) #else void UTCToLocal(utcdate, utctime, locdate, loctime) int utcdate, utctime, *locdate, *loctime; #endif { int diff; int dummy; /* Hack -- not quite right when DST changes. */ if (!CalculateUTC || CalcMinsFromUTC(utcdate, utctime, &diff, &dummy)) diff=MinsFromUTC; utctime += diff; if (utctime < 0) { utctime += 1440; utcdate--; } else if (utctime >= 1440) { utctime -= 1440; utcdate++; } *locdate = utcdate; *loctime = utctime; } /***************************************************************/ /* */ /* SigIntHandler */ /* */ /* For debugging purposes, when sent a SIGINT, we print the */ /* contents of the queue. This does NOT work when the -f */ /* command-line flag is supplied. */ /* */ /* For OS/2, this has to be in the main thread. */ /* */ /***************************************************************/ #ifdef HAVE_QUEUED #ifdef __BORLANDC__ void __cdecl SigIntHandler(int d) #else #ifdef HAVE_PROTOS #ifdef SIGHANDLER_INT_ARG void SigIntHandler(int d) #else void SigIntHandler(void) #endif #else void SigIntHandler() #endif #endif { #ifdef SYSV signal(SIGINT, SigIntHandler); #else #ifdef __BORLANDC__ signal(SIGINT, SIG_DFL); #else #ifdef __OS2__ signal(SIGINT, SIG_ACK); #endif #endif #endif GotSigInt(); #ifndef UNIX exit(0); #endif } #endif /* HAVE_QUEUED */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.