Files
magic/textio/txOutput.c
T
Patrick Kurth ea03883829 Fixed unused-parameters/unused-variables warnings
Added a ARG_UNUSED macro in utils/magic.h, which
produces a simple cast to void to silence the warnings.
The reasons this is used as opposed to an attribute is
that most compilers should support this.
Besides this, the macro can be easily searched for in
the future to potentially remove (where possible) the
unused parameters.
2025-10-10 22:12:19 +02:00

496 lines
10 KiB
C

/*
* txOutput.c --
*
* Handles 'stdout' and 'stderr' output.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/textio/txOutput.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h> /* getenv() */
#include <string.h>
#ifndef SYSV
#include <sys/wait.h>
#endif /* SYSV */
#include <sys/stat.h>
#include <unistd.h>
#include "utils/magsgtty.h"
#include "utils/magic.h"
#include "textio/textio.h"
#include "utils/geometry.h"
#include "textio/txcommands.h"
#include "textio/textioInt.h"
#include "windows/windows.h"
#include "graphics/graphics.h"
#include "utils/paths.h"
#include "utils/utils.h"
#include "utils/malloc.h"
/* When a pipe has been opened to "more", the following variables
* keep track of the file and process. The "TxMoreFile" variable is
* public so that routines like vfprintf() can check it to see if it
* is NULL or not. It is guaranteed to be NULL if we don't want to send
* stuff through more.
*/
FILE * TxMoreFile = NULL;
static bool txPrintFlag = TRUE;
/*
* ----------------------------------------------------------------------------
* txFprintfBasic:
*
* Textio's own version of printf. Not to be used outside of this module.
*
* Tricks:
* Called with a variable number of arguments -- may not be portable.
*
* Results:
* None.
*
* Side effects:
* text appears on stdout on the text terminal
*
* Note:
* Many thanks to Paul Chow at Stanford for getting this to run on
* a Pyramid machine.
* ----------------------------------------------------------------------------
*/
void
txFprintfBasic(FILE *f, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
Vfprintf(f, fmt, args);
va_end(args);
}
/*
* ----------------------------------------------------------------------------
* TxPrintf:
*
* Magic's own version of printf
*
* Tricks:
* Called with a variable number of arguments -- may not be portable.
*
* Results:
* None.
*
* Side effects:
* text appears on stdout on the text terminal
*
* Note:
* Many thanks to Paul Chow at Stanford for getting this to run on
* a Pyramid machine.
* ----------------------------------------------------------------------------
*/
void
TxPrintf(const char *fmt, ...)
{
va_list args;
FILE *f;
if (txPrintFlag)
{
if (TxMoreFile != NULL)
{
f = TxMoreFile;
}
else
{
f = stdout;
}
if (txHavePrompt)
{
TxUnPrompt();
va_start(args, fmt);
Vfprintf(f, fmt, args);
va_end(args);
TxPrompt();
}
else
{
va_start(args, fmt);
Vfprintf(f, fmt, args);
va_end(args);
}
return;
}
}
/*
* ----------------------------------------------------------------------------
* TxPrintString --
*
* A version of printf which writes output into a string.
*
* Results:
* A string which is valid until the next call to TxPrintString().
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
char *
TxPrintString(const char *fmt, ...)
{
va_list args;
static char *outstr = NULL;
static int outlen;
int nchars;
if (outstr == NULL)
{
outlen = 100;
outstr = (char *) mallocMagic((unsigned) (outlen + 1));
}
va_start(args, fmt);
nchars = vsnprintf(outstr, outlen, fmt, args);
va_end(args);
if (nchars >= outlen)
{
outlen = nchars + 1;
freeMagic(outstr);
outstr = (char *) mallocMagic((unsigned) (outlen + 1));
va_start(args, fmt);
vsnprintf(outstr, outlen, fmt, args);
va_end(args);
}
if (nchars == -1)
return NULL;
return outstr;
}
/*
* ----------------------------------------------------------------------------
* TxPrintOn --
*
* Enables TxPrintf() output.
*
* Results:
* Previous value of flag.
*
* ----------------------------------------------------------------------------
*/
bool
TxPrintOn(void)
{
bool oldValue = txPrintFlag;
txPrintFlag = TRUE;
return oldValue;
}
/*
* ----------------------------------------------------------------------------
* TxPrintOff --
*
* Disables TxPrintf() output.
*
* Results:
* Previous value of flag.
*
* ----------------------------------------------------------------------------
*/
bool
TxPrintOff(void)
{
bool oldValue = txPrintFlag;
txPrintFlag = FALSE;
return oldValue;
}
#ifndef MAGIC_WRAPPER
/*
* ----------------------------------------------------------------------------
* TxFlush --
*
* Flush the standard out and error out.
*
* Results:
* None.
*
* ----------------------------------------------------------------------------
*/
void
TxFlushErr(void)
{
(void) fflush(stderr);
}
/*----------------------------------------------------------------------------*/
void
TxFlushOut(void)
{
(void) fflush(stdout);
}
/*----------------------------------------------------------------------------*/
void
TxFlush(void)
{
TxFlushOut();
TxFlushErr();
}
#endif
/*
* ----------------------------------------------------------------------------
* TxError:
*
* Magic's own version of printf, but it goes to stderr
*
* Tricks:
* Called with a variable number of arguments -- may not be portable.
*
* Results:
* None.
*
* Side effects:
* text appears on stderr on the text terminal
*
* Note:
* Many thanks to Paul Chow at Stanford for getting this to run on
* a Pyramid machine.
* ----------------------------------------------------------------------------
*/
void
TxError(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
TxErrorV(fmt, args);
va_end(args);
}
void
TxErrorV(const char *fmt, va_list args)
{
FILE *f;
TxFlushOut();
if (TxMoreFile != NULL)
f = TxMoreFile;
else
f = stderr;
if (txHavePrompt)
{
TxUnPrompt();
Vfprintf(f, fmt, args);
TxPrompt();
}
else {
Vfprintf(f, fmt, args);
}
TxFlushErr();
}
#ifndef MAGIC_WRAPPER
/*
* ----------------------------------------------------------------------------
*
* TxUseMore --
*
* This procedure forks a "more" process and causes TxError and TxPrintf
* to send output through it.
*
* Results:
* None.
*
* Side effects:
* A file is opened. When the caller is finished with output,
* it must call TxStopMore to clean up the process.
*
* ----------------------------------------------------------------------------
*/
void
TxUseMore(void)
{
int pipeEnds[2];
int moreRunning = TRUE;
static int moreMsg = FALSE;
const char *pagername, *pagerpath, *useenv = NULL;
struct stat buf;
ASSERT(TxMoreFile == NULL, "TxUseMore");
/* Determine if "more" executable exists and is world executable */
/* before attempting a fork. Check environment variable PAGER */
/* first before defaulting to the built-in value PAGERDIR */
/* (see utils/paths.h). */
if ((useenv = getenv("PAGER")) == NULL)
{
char *tmp = (char *) mallocMagic((unsigned) (strlen(PAGERDIR) + 1));
strcpy(tmp, PAGERDIR);
pagerpath = tmp;
}
else
pagerpath = useenv;
if ((stat(pagerpath, &buf) < 0) || !(buf.st_mode & S_IXOTH))
{
if (!moreMsg)
{
TxError("Couldn't execute %s to filter output.\nTry setting "
"environment variable PAGER to your favorite pager\n\n",
pagerpath);
moreMsg = TRUE;
}
goto done;
}
pipe(pipeEnds);
FORK(txMorePid);
/* In the child process, move the pipe input to standard input,
* delete the output stream, and then run "more".
*/
if (txMorePid == 0)
{
char *argv[100];
close(pipeEnds[1]);
dup2(pipeEnds[0], 0);
if ((pagername = strrchr(pagerpath, '/')) != (char *) 0)
pagername++;
else
pagername = pagerpath;
execl(pagerpath, pagername, NULL);
/* Something went very wrong if it gets here. */
_exit(-1);
}
/* This is the parent process. Close the input descriptor and make
* an official FILE for the output descriptor.
*/
close(pipeEnds[0]);
TxMoreFile = fdopen(pipeEnds[1], "w");
done:
if (useenv == NULL) freeMagic((char*)pagerpath);
return;
}
/*
* ----------------------------------------------------------------------------
*
* TxStopMore --
*
* Close the pipe connecting us to a "more" process and wait for
* the "more" process to die.
*
* Results:
* None.
*
* Side effects:
* The connection to more is closed.
*
* ----------------------------------------------------------------------------
*/
void
TxStopMore(void)
{
/* TxMoreFile may be NULL if the "more" executable was not found */
if (TxMoreFile == NULL) return;
/* Close the pipe. */
ASSERT(txMorePid != 0, "TxStopMore");
fclose(TxMoreFile);
TxMoreFile = NULL;
/* Wait until there are no child processes left. This is a bit
* of a kludge, and may screw up if other child processes are
* created for other purposes at the same time, but I can't see
* any way around it.
*/
WaitPid (txMorePid, 0);
txMorePid = 0;
}
#endif /* !MAGIC_WRAPPER */
#ifdef NEED_VFPRINTF
int
vfprintf(FILE *iop, const char *fmt, va_list args_in)
{
va_list ap;
int len;
#if defined(MIPSEB) && defined(SYSTYPE_BSD43)
unsigned char localbuf[BUFSIZ];
#else
char localbuf[BUFSIZ];
#endif
va_copy(ap, args_in);
if (iop->_flag & _IONBF) {
iop->_flag &= ~_IONBF;
iop->_ptr = iop->_base = localbuf;
len = _doprnt(fmt, ap, iop);
(void) fflush(iop);
iop->_flag |= _IONBF;
iop->_base = NULL;
iop->_bufsiz = 0;
iop->_cnt = 0;
} else
len = _doprnt(fmt, ap, iop);
va_end(ap);
return (ferror(iop) ? EOF : len);
}
#endif /* NEED_VFPRINTF */