/************************************************************************/
/* */
/* Platform -- Handle platform-specific functions (Linux version) */
/* */
/* This module is part of behoffski's attempt to provide */
/* utterly portable sources using link-time or run-time binding */
/* instead of using the preprocessor at compile time. */
/* */
/* This version uses ANSI escape sequences to select */
/* highlighting attributes, similar to (but less sophisticated */
/* than) the "colorized" ls. However, in common with */
/* ls, it may leave the terminal with incorrect colour */
/* settings if output is interrupted while displaying */
/* highlighted text. */
/* */
/* Copyright (C) 1995-2000 Grouse Software. All rights reserved. */
/* Written for Grouse by behoffski (Brenton Hoff). */
/* */
/* Free software: no warranty; use anywhere is ok; spread the */
/* sources; note any mods; share variations and derivatives */
/* (including sending to behoffski@grouse.com.au). */
/* */
/************************************************************************/
#include "ascii.h"
#include "bakslash.h"
#include "compdef.h"
#include "fastfile.h"
#include "ggrep.h"
#include "main.h"
#include "matchgcc.h"
#include "matcheng.h"
#include "platform.h"
#include "regexp00.h"
#include "retable.h"
#include "scanfile.h"
#include "stbm.h"
#include "stbmshim.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tbldisp.h"
#include "tracery.h"
#include <unistd.h>
/*Small memory pool parameters*/
#define PLATFORM_SMALL_POOL_SIZE 16384 /*bytes*/
#define PLATFORM_ALIGN_SIZE 32
/*Hacky console escapes for highlighting*/
#define HIGHLIGHT_ON() printf("\033[0;47;1;36m")
#define HIGHLIGHT_OFF() printf("\033[m")
typedef struct {
/*Flag indicating whether output can comprehend ANSI colours*/
BOOL ANSIColours;
CHAR *pProgName;
/*Small memory pool to optimise malloc calls*/
void *pSmallPool;
UINT PoolSpaceLeft;
} PLATFORM_MODULE_CONTEXT;
module_scope PLATFORM_MODULE_CONTEXT gPlatform;
/************************************************************************/
/* */
/* Display -- Display matching line */
/* */
/************************************************************************/
module_scope BOOL
Platform_Display(MatchEng_Details *pDetails)
{
UINT32 ByteOffset;
/*Display extra identifying info requested by client*/
if (pDetails->ReportingOptions & MATCHENG_RPT_FILENAME) {
fputs(pDetails->pFilename, stdout);
fputc(':', stdout);
}
if (pDetails->ReportingOptions & MATCHENG_RPT_LINENUMBER) {
fprintf(stdout, "%lu:", pDetails->LineNr);
}
if (pDetails->ReportingOptions & MATCHENG_RPT_BYTEOFFSET) {
/*Work out and report match line's byte offset*/
ByteOffset = pDetails->BufferOffset +
(pDetails->pLineStart - pDetails->pBufferStart);
fprintf(stdout, "%lu:", ByteOffset);
}
/*Write line (plus trailing LF) to stdout as binary data*/
fwrite(pDetails->pLineStart,
1,
pDetails->pLineEnd - pDetails->pLineStart,
stdout);
/*Tell search engine to keep going*/
return TRUE;
} /*Display*/
/************************************************************************/
/* */
/* DisplayHighlighted -- Display line, highlighting matching text */
/* */
/************************************************************************/
module_scope BOOL
Platform_DisplayHighlighted(MatchEng_Details *pDetails)
{
UINT32 ByteOffset;
/*Display extra identifying info requested by client*/
if (pDetails->ReportingOptions & MATCHENG_RPT_FILENAME) {
fputs(pDetails->pFilename, stdout);
putchar(':');
}
if (pDetails->ReportingOptions & MATCHENG_RPT_LINENUMBER) {
/*Report total line count*/
printf("%lu:", pDetails->LineNr);
}
if (pDetails->ReportingOptions & MATCHENG_RPT_BYTEOFFSET) {
/*Work out and report match line's byte offset*/
ByteOffset = pDetails->BufferOffset +
(pDetails->pLineStart - pDetails->pBufferStart);
fprintf(stdout, "%lu:", ByteOffset);
}
if (pDetails->ReportingOptions & MATCHENG_RPT_MARKER_FLAG) {
/*Display line up to beginning of match with marker*/
fputc(pDetails->MarkerChar, stdout);
fwrite(pDetails->pLineStart,
1,
pDetails->pMatchStart - pDetails->pLineStart,
stdout);
/*?? Should encode binary characters*/
/*Write matching part of line with markers*/
fputc(pDetails->MarkerChar, stdout);
fwrite(pDetails->pMatchStart,
1,
pDetails->pMatchEnd - pDetails->pMatchStart,
stdout);
fputc(pDetails->MarkerChar, stdout);
/*Write remainder of line (include delimiter if appropriate)*/
fwrite(pDetails->pMatchEnd,
1,
pDetails->pLineEnd - pDetails->pMatchEnd,
stdout);
} else {
/*Display line up to beginning of match*/
fwrite(pDetails->pLineStart,
1,
pDetails->pMatchStart - pDetails->pLineStart,
stdout);
/*Write matching part of line with highlighting*/
if (gPlatform.ANSIColours) {
HIGHLIGHT_ON();
}
fwrite(pDetails->pMatchStart,
1,
pDetails->pMatchEnd - pDetails->pMatchStart,
stdout);
if (gPlatform.ANSIColours) {
HIGHLIGHT_OFF();
}
/*Write remainder of line (include delimiter if appropriate)*/
fwrite(pDetails->pMatchEnd,
1,
pDetails->pLineEnd - pDetails->pMatchEnd + 1,
stdout);
}
/*Tell search engine to keep going*/
return TRUE;
} /*DisplayHighlighted*/
/************************************************************************/
/* */
/* DisplayFilename -- Display file name and match details */
/* */
/************************************************************************/
module_scope BOOL
Platform_DisplayFilename(MatchEng_Details *pDetails)
{
/*Has filename output been selected?*/
if (pDetails->ReportingOptions & MATCHENG_RPT_FILENAME) {
/*Yes, is line counting enabled as well?*/
if (pDetails->ReportingOptions & MATCHENG_RPT_LINECOUNT) {
/*Yes, report it now as well*/
printf("%s:%lu\n", pDetails->pFilename,
pDetails->LineMatchCount);
} else {
/*No, report file name only (plus LF)*/
printf("%s\n", pDetails->pFilename);
}
} else {
/*Caller must want line count display without filename*/
printf("%lu\n", pDetails->LineMatchCount);
}
/*Search should abandon this file as it has been reported*/
return FALSE;
} /*DisplayFilename*/
/************************************************************************/
/* */
/* main -- Set up platform-specific things before invoking program */
/* */
/************************************************************************/
public_scope int
main(int argc, char **argv)
{
int Result;
char *pProg;
/*Phase 1: Prepare module internals without referencing others*/
gPlatform.ANSIColours = FALSE;
/*Was the program name supplied in the argument list?*/
gPlatform.pProgName = "ggrep";
pProg = argv[0];
if (pProg != NULL) {
/*Yes, use the filename (last) component of the name*/
gPlatform.pProgName = pProg;
pProg = strrchr(pProg, '/');
if (pProg != NULL) {
gPlatform.pProgName = pProg + 1;
}
}
/*Initialise the small malloc pool*/
gPlatform.pSmallPool = malloc(PLATFORM_SMALL_POOL_SIZE);
if (gPlatform.pSmallPool == NULL) {
/*Sorry, not enough memory to run*/
fprintf(stderr, "?? Unable to allocate small pool!");
return MAIN_RETURN_FAULT;
}
gPlatform.PoolSpaceLeft = PLATFORM_SMALL_POOL_SIZE;
/*Basic initialisation of each module*/
Bakslash_Init();
FastFile_Init();
GGrep_Init();
MatchGCC_Init();
RegExp_Init();
RETable_Init();
ScanFile_Init();
STBM_Init();
STBMShim_Init();
Tracery_Init();
/*Phase 2: Notify other modules of existence as appropriate*/
/* Also acquire permanent resources*/
/*Start modules going (get resources and chat to other modules)*/
if (! RETable_Start()) {
fprintf(stderr, "%s: Unable to start RETable!\n",
gPlatform.pProgName);
return MAIN_RETURN_FAULT;
}
/*Set up ScanFile for operation and acquire memory*/
if (! ScanFile_Start())
{
/*Sorry, ScanFile/FastFile was unable to prepare*/
fprintf(stderr, "%s: Not enough memory to scan input!\n",
gPlatform.pProgName);
return MAIN_RETURN_FAULT;
}
/*Specify functions to display matches and/or filenames*/
ScanFile_OutputFunctions(Platform_Display,
Platform_DisplayHighlighted,
Platform_DisplayFilename);
/*We can only use GNU C search engine (faster but non-ANSI)*/
ScanFile_MatchFunction(MatchGCC_Match);
/*Acquire entry points for actions to use in state tables*/
MatchGCC_Match((MatchEng_Spec *) &gMatchEngAct, NULL, NULL);
/*Inform table display facility of action values*/
TblDisp_PrepareLabels();
/*Find out whether output is likely to want to see ANSI escape codes*/
gPlatform.ANSIColours = isatty(fileno(stdout));
#ifdef TRACERY_ENABLED
/*Create Tracery entries for all modules*/
Tracery_Register("s", "Scanner", NULL, ScanFile_TraceryLink);
Tracery_Register("m", "Matcher", NULL, MatchGCC_TraceryLink);
Tracery_Register("f", "FastFile", NULL, FastFile_TraceryLink);
#endif /*TRACERY_ENABLED*/
/*Phase 3: Analyse request and configure everything (see ggrep)*/
/*Phase 4: Execute request (see ggrep)*/
/*Invoke main routine and report return code*/
Result = GGrep_main(argc, argv);
return Result;
} /*main*/
/************************************************************************/
/* */
/* ProgramName -- Report the name used to invoke us */
/* */
/* Reports the program name, based on the non-directory bits */
/* of the filename reported by argv[0]. */
/* */
/************************************************************************/
public_scope CHAR *
Platform_ProgramName(void)
{
/*Merely report what main() recorded*/
return gPlatform.pProgName;
} /*ProgramName*/
/************************************************************************/
/* */
/* SmallMalloc -- Optimised malloc for small areas */
/* */
/* malloc is a slow system call, and so we should try to */
/* minimise the number of times it's called if we're really */
/* desperate to optimise for speed. This interface doles */
/* memory from a modest pool, and hands any request larger */
/* then the available pool to malloc to handle. Hopefully */
/* this will speed things up somewhat. */
/* */
/************************************************************************/
public_scope void *
Platform_SmallMalloc(size_t size)
{
void *pPool;
/*Round the request size up to the next alignment boundary*/
size += PLATFORM_ALIGN_SIZE + 1;
size -= size % PLATFORM_ALIGN_SIZE;
/*Is this request larger than the available pool?*/
if (size > gPlatform.PoolSpaceLeft) {
/*Yes, use malloc to serve the request*/
return malloc(size);
}
/*Okay, carve off pool space and report it to caller*/
pPool = gPlatform.pSmallPool;
gPlatform.pSmallPool = ((BYTE *) gPlatform.pSmallPool) + size;
gPlatform.PoolSpaceLeft -= size;
return pPool;
} /*SmallMalloc*/
/************************************************************************/
/* */
/* SmallFree -- Free space issued by SmallMalloc */
/* */
/************************************************************************/
public_scope void
Platform_SmallFree(void *pMem)
{
/*Sorry, we can't free at this stage*/
} /*SmallFree*/