mirror of
https://github.com/lcn2/calc.git
synced 2025-08-16 01:03:29 +03:00
Converted all ASCII tabs to ASCII spaces using a 8 character tab stop, for all files, except for all Makefiles (plus rpm.mk). The `git diff -w` reports no changes.
331 lines
9.6 KiB
C
331 lines
9.6 KiB
C
/*
|
|
* help - display help for calc
|
|
*
|
|
* Copyright (C) 1999-2007,2014,2018,2021 Landon Curt Noll
|
|
*
|
|
* Calc is open software; you can redistribute it and/or modify it under
|
|
* the terms of the version 2.1 of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* Calc is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
|
* Public License for more details.
|
|
*
|
|
* A copy of version 2.1 of the GNU Lesser General Public License is
|
|
* distributed with calc under the filename COPYING-LGPL. You should have
|
|
* received a copy with calc; if not, write to Free Software Foundation, Inc.
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Under source code control: 1997/09/14 10:58:30
|
|
* File existed as early as: 1997
|
|
*
|
|
* chongo <was here> /\oo/\ http://www.isthe.com/chongo/
|
|
* Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <signal.h>
|
|
#include <sys/errno.h>
|
|
|
|
#include "calc.h"
|
|
#include "conf.h"
|
|
#include "lib_calc.h"
|
|
|
|
#include "have_unistd.h"
|
|
#if defined(HAVE_UNISTD_H)
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
# define popen _popen
|
|
# define pclose _pclose
|
|
#endif
|
|
|
|
|
|
#include "banned.h" /* include after system header <> includes */
|
|
|
|
|
|
/*
|
|
* some help topics are symbols, so we alias them to nice filenames
|
|
*/
|
|
STATIC struct help_alias {
|
|
char *topic;
|
|
char *filename;
|
|
} halias[] = {
|
|
/* We sort the list below via: sort -d -u */
|
|
{"=", "address"},
|
|
{"->", "arrow"},
|
|
{"=", "assign"},
|
|
{"*", "dereference"},
|
|
{"%", "mod"},
|
|
{".", "oldvalue"},
|
|
{"#", "pound"},
|
|
{"//", "quo"},
|
|
{"COPYING_LGPL", "COPYING-LGPL"},
|
|
{"COPYLEFT", "copyright"},
|
|
{"COPYRIGHT", "copyright"},
|
|
{"Copyleft", "copyright"},
|
|
{"Copyright", "copyright"},
|
|
{"abort", "command"},
|
|
{"cd", "command"},
|
|
{"copy", "blkcpy"},
|
|
{"copying", "COPYING"},
|
|
{"copying-lgpl", "COPYING-LGPL"},
|
|
{"define", "command"},
|
|
{"dm2d", "dms2d"},
|
|
{"exit", "command"},
|
|
{"gm2g", "gms2g"},
|
|
{"hm2d", "hms2d"},
|
|
{"man", "calc"},
|
|
{"question", "questions"},
|
|
{"quit", "command"},
|
|
{"read", "command"},
|
|
{"release", "releases"},
|
|
{"show", "command"},
|
|
{"stdlib", "resource"},
|
|
{"usage", "calc"},
|
|
{"write", "command"},
|
|
|
|
/* MUST BE LAST! */
|
|
{NULL, NULL}
|
|
};
|
|
|
|
|
|
/*
|
|
* external values
|
|
*/
|
|
EXTERN char *pager; /* $PAGER or default */
|
|
|
|
|
|
/*
|
|
* page_file - output an open file thru a pager
|
|
*
|
|
* The popen() below is fairly safe. The $PAGER environment variable
|
|
* (supplied by the user) is the command we need to run without args.
|
|
* True, the user could set $PAGER is a bogus prog ... but if -m is
|
|
* 5 or 7 (read and exec allowed), then the calc is given ``permission''
|
|
* to open the help file for reading as well as to exec the pager!
|
|
*
|
|
* given:
|
|
* stream open file stream of the file to send to the pager
|
|
*/
|
|
S_FUNC void
|
|
page_file(FILE *stream)
|
|
{
|
|
FILE *cmd; /* pager command */
|
|
char buf[BUFSIZ+1]; /* I/O buffer */
|
|
char *fgets_ret; /* fgets() return value */
|
|
|
|
/*
|
|
* flush any pending I/O
|
|
*/
|
|
fflush(stderr);
|
|
fflush(stdout);
|
|
fflush(stdin);
|
|
|
|
/*
|
|
* form a write pipe to a pager
|
|
*/
|
|
if (pager == NULL || pager[0] == '\0') {
|
|
cmd = stdout;
|
|
} else {
|
|
cmd = popen(pager, "w");
|
|
}
|
|
if (cmd == NULL) {
|
|
fprintf(stderr, "unable form pipe to pager: %s", pager);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* read the help file and send non-## lines to the pager
|
|
* until EOF or error
|
|
*/
|
|
buf[BUFSIZ] = '\0';
|
|
do {
|
|
|
|
/*
|
|
* read the next line that does not begin with ##
|
|
*/
|
|
buf[0] = '\0';
|
|
while ((fgets_ret = fgets(buf, BUFSIZ, stream)) != NULL &&
|
|
buf[0] == '#' && buf[1] == '#') {
|
|
}
|
|
|
|
/*
|
|
* stop reading when we reach EOF (or error) on help file
|
|
*/
|
|
if (fgets_ret == NULL) {
|
|
fflush(cmd);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* write the line to pager, if possible
|
|
*
|
|
* We have to use fprintf() instead of fputs() because
|
|
* on NetBSD, fputs() function returns 0 on success and
|
|
# EOF on error. *sigh*
|
|
*/
|
|
} while (fprintf(cmd, "%s", buf) > 0);
|
|
|
|
/*
|
|
* all done, EOF or error, so just clean up
|
|
*/
|
|
(void) pclose(cmd);
|
|
fflush(stderr);
|
|
fflush(stdout);
|
|
fflush(stdin);
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* givehelp - display a help file
|
|
*
|
|
* given:
|
|
* type the type of help to give, NULL => index
|
|
*/
|
|
void
|
|
givehelp(char *type)
|
|
{
|
|
struct help_alias *p; /* help alias being considered */
|
|
FILE *stream; /* help file stream */
|
|
char *helppath; /* path to the help file */
|
|
char *c;
|
|
size_t snprintf_len; /* malloced snprintf buffer length */
|
|
|
|
/*
|
|
* check permissions to see if we are allowed to help
|
|
*/
|
|
if (!allow_exec || !allow_read) {
|
|
fprintf(stderr,
|
|
"sorry, help is only allowed with -m mode 5 or 7\n");
|
|
return;
|
|
}
|
|
|
|
/* catch the case where we just print the index */
|
|
if (type == NULL) {
|
|
type = DEFAULTCALCHELP; /* the help index file */
|
|
}
|
|
|
|
/* alias the type of help, if needed */
|
|
for (p=halias; p->topic; ++p) {
|
|
if (strcmp(type, p->topic) == 0) {
|
|
type = p->filename;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* sanity check on name
|
|
*/
|
|
/* look for /. or a leading . */
|
|
if (strstr(type, "/.") != NULL || type[0] == '.') {
|
|
fprintf(stderr, "bad help name\n");
|
|
return;
|
|
}
|
|
/* look for chars that could be shell meta chars */
|
|
for (c = type; *c; ++c) {
|
|
switch ((int)*c) {
|
|
case '+':
|
|
case ',':
|
|
case '-':
|
|
case '.':
|
|
case '/':
|
|
case '_':
|
|
break;
|
|
default:
|
|
if (!isascii((int)*c) || !isalnum((int)*c)) {
|
|
fprintf(stderr, "bogus char in help name\n");
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* special case for Copyright and Copyleft
|
|
*/
|
|
if (strcmp(type, "copyright") == 0) {
|
|
fputs(Copyright, stdout);
|
|
fflush(stdout);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* open the helpfile (looking in HELPDIR first)
|
|
*/
|
|
snprintf_len = strlen(calc_helpdir)+1+strlen(type) + 1;
|
|
helppath = (char *)malloc(snprintf_len+1);
|
|
if (helppath == NULL) {
|
|
fprintf(stderr, "malloc failure in givehelp #0\n");
|
|
return;
|
|
}
|
|
snprintf(helppath, snprintf_len, "%s/%s", calc_helpdir, type);
|
|
helppath[snprintf_len] = '\0'; /* paranoia */
|
|
errno = 0;
|
|
stream = fopen(helppath, "r");
|
|
if (stream != NULL) {
|
|
|
|
/*
|
|
* we have the help file open, now display it
|
|
*/
|
|
page_file(stream);
|
|
(void) fclose(stream);
|
|
|
|
#if defined(CUSTOM)
|
|
/*
|
|
* open the helpfile (looking in CUSTOMHELPDIR last)
|
|
*/
|
|
} else {
|
|
char *cust_helppath; /* path to the custom help file */
|
|
size_t cust_snprintf_len; /* malloced custom snprintf buf len */
|
|
|
|
cust_snprintf_len =
|
|
strlen(calc_customhelpdir)+1+strlen(type) + 1;
|
|
cust_helppath = (char *)malloc(cust_snprintf_len+1);
|
|
if (cust_helppath == NULL) {
|
|
fprintf(stderr, "malloc failure for givehelp #1\n");
|
|
return;
|
|
}
|
|
snprintf(cust_helppath, cust_snprintf_len,
|
|
"%s/%s", calc_customhelpdir, type);
|
|
cust_helppath[cust_snprintf_len] = '\0'; /* paranoia */
|
|
errno = 0;
|
|
stream = fopen(cust_helppath, "r");
|
|
if (stream != NULL) {
|
|
|
|
/*
|
|
* we have the help file open, now display it
|
|
*/
|
|
page_file(stream);
|
|
(void) fclose(stream);
|
|
|
|
/* unable to open help file */
|
|
} else {
|
|
fprintf(stderr, "unable to open help file: %s - %s\n",
|
|
type, strerror(errno));
|
|
}
|
|
free(cust_helppath);
|
|
cust_helppath = NULL;
|
|
|
|
#else /* CUSTOM */
|
|
/* unable to open help file */
|
|
} else {
|
|
fprintf(stderr, "unable to open help file: %s - %s\n",
|
|
type, strerror(errno));
|
|
#endif /* CUSTOM */
|
|
}
|
|
|
|
/*
|
|
* cleanup
|
|
*/
|
|
free(helppath);
|
|
helppath = NULL;
|
|
return;
|
|
}
|