Restrict locale settings to the file they occur in

This prevents LANG= in an included file from affecting the interpretation
of month and day names in the including file.

Make the internal pre-processor accept white space between the "#" at
the start of the line and the keyword for better compatibility with cpp.

Add support for the cpp keywords #warning and #error.

MFC after:	3 days
This commit is contained in:
Stefan Eßer 2020-11-05 08:58:21 +00:00
parent 20172854ab
commit 0357fa2632
4 changed files with 63 additions and 32 deletions

View File

@ -28,7 +28,7 @@
.\" @(#)calendar.1 8.1 (Berkeley) 6/29/93 .\" @(#)calendar.1 8.1 (Berkeley) 6/29/93
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd November 4, 2020 .Dd November 5, 2020
.Dt CALENDAR 1 .Dt CALENDAR 1
.Os .Os
.Sh NAME .Sh NAME
@ -199,13 +199,14 @@ file is preprocessed by a limited subset of
internally, allowing the inclusion of shared files such as internally, allowing the inclusion of shared files such as
lists of company holidays or meetings. lists of company holidays or meetings.
This limited subset consists of \fB#include\fR, \fB#define\fR, This limited subset consists of \fB#include\fR, \fB#define\fR,
\fB#undef\fR, \fB#ifdef\fR, \fB#ifndef\fR, and \fB#else\fR. \fB#undef\fR, \fB#ifdef\fR, \fB#ifndef\fR, \fB#else\fR, \fB#warning\fR,
and \fB#error\fR.
.Pp .Pp
Conditions can be nested and the consistency of opening and closing Conditions can be nested and the consistency of opening and closing
instructions is checked. instructions is checked.
Only the first word after #define is used as the name of the Only the first word after #define is used as the name of the
condition variable being defined. condition variable being defined.
More than word following #ifdef, #ifndef, or #undef is a ayntax More than word following #ifdef, #ifndef, or #undef is considered a syntax
error, since names cannot include white-space. error, since names cannot include white-space.
Included files are parsed in a global scope with regard to the condition Included files are parsed in a global scope with regard to the condition
variables being defined or tested therein. variables being defined or tested therein.

View File

@ -130,7 +130,6 @@ struct event {
int month; int month;
int day; int day;
int var; int var;
char *date;
char *text; char *text;
char *extra; char *extra;
struct event *next; struct event *next;

View File

@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$");
#include <iconv.h> #include <iconv.h>
#include <errno.h> #include <errno.h>
#include <langinfo.h> #include <langinfo.h>
#include <locale.h>
static iconv_t conv = (iconv_t)-1; static iconv_t conv = (iconv_t)-1;
static char *currentEncoding = NULL; static char *currentEncoding = NULL;
@ -204,13 +203,7 @@ event_print_all(FILE *fp)
struct tm tm; struct tm tm;
char dbuf[80]; char dbuf[80];
static int d_first; static int d_first;
const char *lang;
lang = getenv("LANG");
if (lang == NULL)
lang = "C";
if (setlocale(LC_ALL, lang) == NULL)
(void)setlocale(LC_ALL, "C");
d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
while (walkthrough_dates(&e) != 0) { while (walkthrough_dates(&e) != 0) {

View File

@ -172,6 +172,16 @@ cal_path(void)
#define WARN1(format, arg1) \ #define WARN1(format, arg1) \
warnx(format " in %s line %d", arg1, cal_path(), cal_line) warnx(format " in %s line %d", arg1, cal_path(), cal_line)
static char*
cmptoken(char *line, const char* token)
{
char len = strlen(token);
if (strncmp(line, token, len) != 0)
return NULL;
return (line + len);
}
static int static int
token(char *line, FILE *out, int *skip, int *unskip) token(char *line, FILE *out, int *skip, int *unskip)
{ {
@ -181,7 +191,10 @@ token(char *line, FILE *out, int *skip, int *unskip)
const char *this_cal_file; const char *this_cal_file;
int this_cal_line; int this_cal_line;
if (strncmp(line, "endif", 5) == 0) { while (isspace(*line))
line++;
if (cmptoken(line, "endif")) {
if (*skip + *unskip == 0) { if (*skip + *unskip == 0) {
WARN0("#endif without prior #ifdef or #ifndef"); WARN0("#endif without prior #ifdef or #ifndef");
return (T_ERR); return (T_ERR);
@ -194,8 +207,8 @@ token(char *line, FILE *out, int *skip, int *unskip)
return (T_OK); return (T_OK);
} }
if (strncmp(line, "ifdef", 5) == 0) { walk = cmptoken(line, "ifdef");
walk = line + 5; if (walk != NULL) {
sep = trimlr(&walk); sep = trimlr(&walk);
if (*walk == '\0') { if (*walk == '\0') {
@ -217,8 +230,8 @@ token(char *line, FILE *out, int *skip, int *unskip)
return (T_OK); return (T_OK);
} }
if (strncmp(line, "ifndef", 6) == 0) { walk = cmptoken(line, "ifndef");
walk = line + 6; if (walk != NULL) {
sep = trimlr(&walk); sep = trimlr(&walk);
if (*walk == '\0') { if (*walk == '\0') {
@ -240,8 +253,8 @@ token(char *line, FILE *out, int *skip, int *unskip)
return (T_OK); return (T_OK);
} }
if (strncmp(line, "else", 4) == 0) { walk = cmptoken(line, "else");
walk = line + 4; if (walk != NULL) {
(void)trimlr(&walk); (void)trimlr(&walk);
if (*walk != '\0') { if (*walk != '\0') {
@ -267,9 +280,8 @@ token(char *line, FILE *out, int *skip, int *unskip)
if (*skip != 0) if (*skip != 0)
return (T_OK); return (T_OK);
if (strncmp(line, "include", 7) == 0) { walk = cmptoken(line, "include");
walk = line + 7; if (walk != NULL) {
(void)trimlr(&walk); (void)trimlr(&walk);
if (*walk == '\0') { if (*walk == '\0') {
@ -306,10 +318,10 @@ token(char *line, FILE *out, int *skip, int *unskip)
return (T_OK); return (T_OK);
} }
if (strncmp(line, "define", 6) == 0) { walk = cmptoken(line, "define");
if (walk != NULL) {
if (definitions == NULL) if (definitions == NULL)
definitions = sl_init(); definitions = sl_init();
walk = line + 6;
sep = trimlr(&walk); sep = trimlr(&walk);
*sep = '\0'; *sep = '\0';
@ -323,9 +335,9 @@ token(char *line, FILE *out, int *skip, int *unskip)
return (T_OK); return (T_OK);
} }
if (strncmp(line, "undef", 5) == 0) { walk = cmptoken(line, "undef");
if (walk != NULL) {
if (definitions != NULL) { if (definitions != NULL) {
walk = line + 5;
sep = trimlr(&walk); sep = trimlr(&walk);
if (*walk == '\0') { if (*walk == '\0') {
@ -345,8 +357,32 @@ token(char *line, FILE *out, int *skip, int *unskip)
return (T_OK); return (T_OK);
} }
return (T_PROCESS); walk = cmptoken(line, "warning");
if (walk != NULL) {
(void)trimlr(&walk);
WARN1("Warning: %s", walk);
}
walk = cmptoken(line, "error");
if (walk != NULL) {
(void)trimlr(&walk);
WARN1("Error: %s", walk);
return (T_ERR);
}
WARN1("Undefined pre-processor command \"#%s\"", line);
return (T_ERR);
}
static void
setup_locale(const char *locale)
{
(void)setlocale(LC_ALL, locale);
#ifdef WITH_ICONV
if (!doall)
set_new_encoding();
#endif
setnnames();
} }
#define REPLACE(string, slen, struct_) \ #define REPLACE(string, slen, struct_) \
@ -361,6 +397,7 @@ token(char *line, FILE *out, int *skip, int *unskip)
static int static int
cal_parse(FILE *in, FILE *out) cal_parse(FILE *in, FILE *out)
{ {
char *mylocale = NULL;
char *line = NULL; char *line = NULL;
char *buf; char *buf;
size_t linecap = 0; size_t linecap = 0;
@ -459,12 +496,9 @@ cal_parse(FILE *in, FILE *out)
* and does not run iconv(), this variable has little use. * and does not run iconv(), this variable has little use.
*/ */
if (strncmp(buf, "LANG=", 5) == 0) { if (strncmp(buf, "LANG=", 5) == 0) {
(void)setlocale(LC_ALL, buf + 5); if (mylocale == NULL)
#ifdef WITH_ICONV mylocale = strdup(setlocale(LC_ALL, NULL));
if (!doall) setup_locale(buf + 5);
set_new_encoding();
#endif
setnnames();
continue; continue;
} }
/* Parse special definitions: Easter, Paskha etc */ /* Parse special definitions: Easter, Paskha etc */
@ -538,6 +572,10 @@ cal_parse(FILE *in, FILE *out)
free(line); free(line);
fclose(in); fclose(in);
if (mylocale != NULL) {
setup_locale(mylocale);
free(mylocale);
}
return (0); return (0);
} }