diff --git a/src/calendar.c b/src/calendar.c index 3efa27d7..1566aabd 100644 --- a/src/calendar.c +++ b/src/calendar.c @@ -1239,6 +1239,7 @@ static void GenerateCalEntries(int col) case T_Else: r=DoElse(&p); break; case T_EndIf: r=DoEndif(&p); break; case T_Include: r=DoInclude(&p); break; + case T_IncludeCmd: r=DoIncludeCmd(&p); break; case T_Exit: DoExit(&p); break; case T_Set: r=DoSet(&p); break; case T_Fset: r=DoFset(&p); break; diff --git a/src/files.c b/src/files.c index be38ec21..6c3fe04e 100644 --- a/src/files.c +++ b/src/files.c @@ -96,7 +96,7 @@ static int CacheFile (char const *fname); static void DestroyCache (CachedFile *cf); static int CheckSafety (void); static int PopFile (void); - +static int IncludeCmd(char const *); static void OpenPurgeFile(char const *fname, char const *mode) { DynamicBuffer fname_buf; @@ -477,7 +477,6 @@ static int PopFile(void) if (!Hush && NumIfs) Eprint("%s", ErrMsg[E_MISS_ENDIF]); if (!IStackPtr) return E_EOF; i = &IStack[IStackPtr-1]; - if (i->chain) { int oldRunDisabled = RunDisabled; if (NextChainedFile(i) == OK) { @@ -501,7 +500,7 @@ static int PopFile(void) if (!i->ownedByMe) { RunDisabled |= RUN_NOTOWNER; } - if (!CLine && (i->offset != -1L)) { + if (!CLine && (i->offset != -1L || !strcmp(i->filename, "-"))) { /* We must open the file, then seek to specified position */ if (strcmp(i->filename, "-")) { fp = fopen(i->filename, "r"); @@ -544,6 +543,55 @@ int DoInclude(ParsePtr p) return OK; } +/***************************************************************/ +/* */ +/* DoIncludeCmd */ +/* */ +/* The INCLUDECMD command. */ +/* */ +/***************************************************************/ +int DoIncludeCmd(ParsePtr p) +{ + DynamicBuffer buf; + DynamicBuffer token; + int r; + + int done = 0; + DBufInit(&buf); + DBufInit(&token); + + while(1) { + if ( (r=ParseToken(p, &token)) ) { + DBufFree(&buf); + return r; + } + if (!*DBufValue(&token)) break; + if (done) { + if (DBufPuts(&buf, " ") != OK) { + DBufFree(&buf); + return E_NO_MEM; + } + + } + done = 1; + if (DBufPuts(&buf, DBufValue(&token)) != OK) { + DBufFree(&buf); + return E_NO_MEM; + } + DBufFree(&token); + DBufInit(&token); + } + + if ( (r=IncludeCmd(DBufValue(&buf))) ) { + DBufFree(&buf); + return r; + } + DBufFree(&buf); + NumIfs = 0; + IfFlags = 0; + return OK; +} + #ifdef HAVE_GLOB static int SetupGlobChain(char const *dirname, IncludeStruct *i) { @@ -664,6 +712,88 @@ static int SetupGlobChain(char const *dirname, IncludeStruct *i) } #endif +/***************************************************************/ +/* */ +/* IncludeCmd */ +/* */ +/* Process the INCLUDECMD command - actually do the command */ +/* inclusion. */ +/* */ +/***************************************************************/ +static int IncludeCmd(char const *cmd) +{ + IncludeStruct *i; + DynamicBuffer buf; + char line_no[64]; + FILE *fp2; + int r; + + FreshLine = 1; + if (IStackPtr+1 >= INCLUDE_NEST) return E_NESTED_INCLUDE; + i = &IStack[IStackPtr]; + + if (RunDisabled) return E_RUN_DISABLED; + + /* Synthesize a new filename consisting of existing filename //cmd// lineno */ + snprintf(line_no, sizeof(line_no), "//cmd//%d", LineNo); + line_no[15] = 0; + DBufInit(&buf); + if (DBufPuts(&buf, FileName) != OK) { + DBufFree(&buf); + return E_NO_MEM; + } + if (DBufPuts(&buf, line_no) != OK) { + DBufFree(&buf); + return E_NO_MEM; + } + + fp2 = popen(cmd, "r"); + if (!fp2) { + DBufFree(&buf); + return E_CANT_OPEN; + } + if (FileName) { + i->filename = StrDup(FileName); + if (!i->filename) { + DBufFree(&buf); + return E_NO_MEM; + } + } else { + i->filename = NULL; + } + i->LineNo = LineNo; + i->NumIfs = NumIfs; + i->IfFlags = IfFlags; + i->CLine = CLine; + i->offset = -1L; + i->chain = NULL; + if (RunDisabled & RUN_NOTOWNER) { + i->ownedByMe = 0; + } else { + i->ownedByMe = 1; + } + if (fp) { + i->offset = ftell(fp); + FCLOSE(fp); + } + fp = fp2; + IStackPtr++; + LineNo = 0; + r = CacheFile(DBufValue(&buf)); + if (r == OK) { + fp = NULL; + CLine = CachedFiles->cache; + LineNo = 0; + STRSET(FileName, DBufValue(&buf)); + DBufFree(&buf); + return OK; + } + DBufFree(&buf); + /* We failed */ + PopFile(); + return E_CANT_OPEN; +} + /***************************************************************/ /* */ /* IncludeFile */ diff --git a/src/main.c b/src/main.c index f0e806cb..453acf45 100644 --- a/src/main.c +++ b/src/main.c @@ -243,6 +243,15 @@ static void DoReminders(void) r=DoInclude(&p); purge_handled = 1; break; + case T_IncludeCmd: + /* In purge mode, include closes file, so we + need to echo it here! */ + if (PurgeMode) { + PurgeEchoLine("%s\n", CurLine); + } + r=DoIncludeCmd(&p); + purge_handled = 1; + break; case T_Exit: DoExit(&p); break; case T_Flush: r=DoFlush(&p); break; case T_Set: r=DoSet(&p); break; diff --git a/src/protos.h b/src/protos.h index 5b091b51..78a782cc 100644 --- a/src/protos.h +++ b/src/protos.h @@ -45,6 +45,7 @@ int CopyValue (Value *dest, const Value *src); int ReadLine (void); int OpenFile (char const *fname); int DoInclude (ParsePtr p); +int DoIncludeCmd (ParsePtr p); int IncludeFile (char const *fname); int GetAccessDate (char const *file); int SetAccessDate (char const *fname, int jul); diff --git a/src/token.c b/src/token.c index f2cd5257..cfa15397 100644 --- a/src/token.c +++ b/src/token.c @@ -62,6 +62,7 @@ Token TokArray[] = { { "if", 2, T_If, 0 }, { "iftrig", 6, T_IfTrig, 0 }, { "include", 3, T_Include, 0 }, + { "includecmd", 10, T_IncludeCmd, 0 }, { "january", 3, T_Month, 0 }, { "july", 3, T_Month, 6 }, { "june", 3, T_Month, 5 }, diff --git a/src/types.h b/src/types.h index 76635302..66fc8f64 100644 --- a/src/types.h +++ b/src/types.h @@ -150,7 +150,7 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */ enum TokTypes { T_Illegal, /* Commands first */ - T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_If, T_Else, T_EndIf, + T_Rem, T_Push, T_Pop, T_Preserve, T_Include, T_IncludeCmd, T_If, T_Else, T_EndIf, T_IfTrig, T_ErrMsg, T_Set, T_UnSet, T_Fset, T_Omit, T_Banner, T_Exit, T_WkDay,