Add support for nested conditionals
The previous behavior was to support nested #ifdef and #ifndef, but to return to unconditional parsing after the next #endif, independently of the number of previously parsed conditions. E.g. after "#ifdef A / #ifdef B / #endif" the following lines were unconditially parsed again, independently of A and/or B being defined. The new behavior is to count the level of false conditions and to only restart parsing of calendar entries when the corresponding number of #endif tokens have been seen. In addition to the above, an #else directive has been added, to toggle between parsing and ignoring of the following lines. No validation of the correct use of the condition directives is made. #endif without prior #define or #ifndef is ignored and #else toggles between parsing and skipping of entries. The MFC period has been set to 1 month to allow for a review of the changes and for a discussion, whether these modifications should not be merged at all. No correct input file is parsed differently than before, but if calendar data files are published that use these new features, those data files will not parse correctly on prior versions of this program. MFC after: 1 month
This commit is contained in:
parent
bdc0cb4e2c
commit
19b5c30754
@ -28,7 +28,7 @@
|
||||
.\" @(#)calendar.1 8.1 (Berkeley) 6/29/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd October 25, 2020
|
||||
.Dd October 28, 2020
|
||||
.Dt CALENDAR 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -198,7 +198,13 @@ file is preprocessed by a limited subset of
|
||||
.Xr cpp 1
|
||||
internally, allowing the inclusion of shared files such as
|
||||
lists of company holidays or meetings.
|
||||
This limited subset consists of \fB#include #ifndef #endif\fR and \fB#define\fR.
|
||||
This limited subset consists of \fB#include #ifdef #ifndef #else
|
||||
#endif\fR and \fB#define\fR. Conditions can be nested, but not check
|
||||
for matching begin and end directives is performed.
|
||||
Included files are parsed in their own scope.
|
||||
They have no read or write access to condition variables defined in
|
||||
an outer scope and open conditional blocks are implicitly closed.
|
||||
.Pp
|
||||
If the shared file is not referenced by a full pathname,
|
||||
.Nm
|
||||
searches in the current (or home) directory first, and then in the
|
||||
@ -346,9 +352,12 @@ double-check the start and end time of solar and lunar events.
|
||||
.Sh BUGS
|
||||
The
|
||||
.Nm
|
||||
internal cpp does not support nested conditions and will continue
|
||||
parsing of the input file on the next #endif even in nested contexts.
|
||||
It does only recognise #include, #define, #ifdef and #ifndef.
|
||||
does only recognise the cpp directives #include, #define, #ifdef,
|
||||
#ifndef and #else.
|
||||
It supports nested conditions, but does not perform any validation
|
||||
on the correct use and nesting of conditions.
|
||||
#endif without prior #ifdef or #define is ignored and #else outside
|
||||
a conditional section skips input lines up to the next #endif.
|
||||
.Pp
|
||||
There is no possibility to properly specify the local position
|
||||
needed for solar and lunar calculations.
|
||||
|
@ -140,16 +140,64 @@ cal_fopen(const char *file)
|
||||
}
|
||||
|
||||
static int
|
||||
token(char *line, FILE *out, bool *skip)
|
||||
token(char *line, FILE *out, int *skip)
|
||||
{
|
||||
char *walk, c, a;
|
||||
|
||||
if (strncmp(line, "endif", 5) == 0) {
|
||||
*skip = false;
|
||||
if (*skip > 0)
|
||||
--*skip;
|
||||
return (T_OK);
|
||||
}
|
||||
|
||||
if (*skip)
|
||||
if (strncmp(line, "ifdef", 5) == 0) {
|
||||
walk = line + 5;
|
||||
trimlr(&walk);
|
||||
|
||||
if (*walk == '\0') {
|
||||
warnx("Expecting arguments after #ifdef");
|
||||
return (T_ERR);
|
||||
}
|
||||
|
||||
if (*skip != 0 || definitions == NULL || sl_find(definitions, walk) == NULL)
|
||||
++*skip;
|
||||
|
||||
return (T_OK);
|
||||
}
|
||||
|
||||
if (strncmp(line, "ifndef", 6) == 0) {
|
||||
walk = line + 6;
|
||||
trimlr(&walk);
|
||||
|
||||
if (*walk == '\0') {
|
||||
warnx("Expecting arguments after #ifndef");
|
||||
return (T_ERR);
|
||||
}
|
||||
|
||||
if (*skip != 0 || (definitions != NULL && sl_find(definitions, walk) != NULL))
|
||||
++*skip;
|
||||
|
||||
return (T_OK);
|
||||
}
|
||||
|
||||
if (strncmp(line, "else", 4) == 0) {
|
||||
walk = line + 4;
|
||||
trimlr(&walk);
|
||||
|
||||
if (*walk != '\0') {
|
||||
warnx("Expecting no arguments after #else");
|
||||
return (T_ERR);
|
||||
}
|
||||
|
||||
if (*skip == 0)
|
||||
*skip = 1;
|
||||
else if (*skip == 1)
|
||||
*skip = 0;
|
||||
|
||||
return (T_OK);
|
||||
}
|
||||
|
||||
if (*skip != 0)
|
||||
return (T_OK);
|
||||
|
||||
if (strncmp(line, "include", 7) == 0) {
|
||||
@ -212,36 +260,6 @@ token(char *line, FILE *out, bool *skip)
|
||||
return (T_OK);
|
||||
}
|
||||
|
||||
if (strncmp(line, "ifdef", 5) == 0) {
|
||||
walk = line + 5;
|
||||
trimlr(&walk);
|
||||
|
||||
if (*walk == '\0') {
|
||||
warnx("Expecting arguments after #ifdef");
|
||||
return (T_ERR);
|
||||
}
|
||||
|
||||
if (definitions == NULL || sl_find(definitions, walk) == NULL)
|
||||
*skip = true;
|
||||
|
||||
return (T_OK);
|
||||
}
|
||||
|
||||
if (strncmp(line, "ifndef", 6) == 0) {
|
||||
walk = line + 6;
|
||||
trimlr(&walk);
|
||||
|
||||
if (*walk == '\0') {
|
||||
warnx("Expecting arguments after #ifndef");
|
||||
return (T_ERR);
|
||||
}
|
||||
|
||||
if (definitions != NULL && sl_find(definitions, walk) != NULL)
|
||||
*skip = true;
|
||||
|
||||
return (T_OK);
|
||||
}
|
||||
|
||||
return (T_PROCESS);
|
||||
|
||||
}
|
||||
@ -269,7 +287,7 @@ cal_parse(FILE *in, FILE *out)
|
||||
int month[MAXCOUNT];
|
||||
int day[MAXCOUNT];
|
||||
int year[MAXCOUNT];
|
||||
bool skip = false;
|
||||
int skip = 0;
|
||||
char dbuf[80];
|
||||
char *pp, p;
|
||||
struct tm tm;
|
||||
@ -299,7 +317,7 @@ cal_parse(FILE *in, FILE *out)
|
||||
}
|
||||
}
|
||||
|
||||
if (skip)
|
||||
if (skip != 0)
|
||||
continue;
|
||||
|
||||
buf = line;
|
||||
|
Loading…
Reference in New Issue
Block a user