/* System: Structured text retrieval tool sgrep. Module: output.c Author: Pekka Kilpeläinen & Jani Jaakkola Description: handles outputting of a gc list ( show_gclist() ) Version history: Original version February 1995 by JJ & PK Copyright: University of Helsinki, Dept. of Computer Science Distributed under GNU General Public Lisence See file COPYING for details * Adapted by: Dave Kuhlman dkuhlman@rexx.com * Description: Creates Python structures to be returned as response * to sgrep queries. * */ /* JJ: Completely rewritten in Sep 11 1998. Using memory mapped files now * and much cleaner */ #include #include #include #define SGREP_LIBRARY #include "sgrep.h" #include #include "pysgrep.h" /* ------------------------------------------- */ #define PYSGREP_BUFFLEN 2048 /* ------------------------------------------- */ struct DisplayerStruct { struct SgrepStruct *sgrep; const FileList *files; /* Current region */ int region; /* Current file */ int current_file; int last; /* total length of all files */ /* * When not in stream mode, the output won't start at position 0. * This points out the start of output */ int first_ind; /* Remember last_char in case we need to append newline */ int last_char; int start_warned; /* Has warnings about too long regions been given ? */ int end_warned; PyObject * stream; /* The output stream to which we are printing * A Python file object. */ /* The mapped file */ char *map; size_t map_size; }; /* ------------------------------------------- */ /* gdk: Private function declarations: */ static const char * py_get_file_region(Displayer *displayer,int file, unsigned int start, unsigned int len); static void py_show_file_region(Displayer *displayer,int file, unsigned int start,unsigned int len); static void py_check_region(Displayer *displayer, int *start, int *len); static int py_locate_file_num(Displayer *displayer, int start); static const char * py_fetch_region(Displayer *d,Region *region, int *size); static void py_show_region(Displayer *displayer,int start,int len); static void py_expand(Displayer *displayer, int ch, Region r); static void py_escape(Displayer *displayer,int ch); static int py_display_gc_list(Displayer *displayer,RegionList *l); static void py_init_displayer(Displayer *displayer,SgrepData *sgrep, FileList *files); static void py_clean_up_displayer(Displayer *displayer); static Displayer * py_new_displayer(SgrepData *sgrep, FileList *files); static void py_delete_displayer(Displayer *d); int py_write_region_list( struct SgrepStruct * sgrep, RegionList * list, FileList * files ); /* ------------------------------------------- */ /* * Prints a region from file. If necessary opens a new file. Only one file * is kept open at a time. s and e are offsets into one file, not into whole * input stream. */ const char * py_get_file_region(Displayer *displayer,int file, unsigned int start, unsigned int len) { SGREPDATA(displayer); if (displayer->current_file!=file) { /* File changed. */ if (displayer->map) { /* Unmap previous file */ unmap_file(sgrep,displayer->map,displayer->map_size); displayer->map=NULL; displayer->map_size=0; } /* FIXME: handle stdin */ displayer->current_file=file; displayer->map_size=map_file(sgrep,flist_name(displayer->files, displayer->current_file), (void **)&displayer->map); } if (displayer->map==NULL) return NULL; /* Nothing to do without a map */ if (start>=displayer->map_size || start+len>displayer->map_size) { sgrep_error(sgrep,"File '%s' truncated?\n", flist_name(displayer->files,file)); return NULL; } return displayer->map+start; } /* ------------------------------------------- */ void py_show_file_region(Displayer *displayer,int file, unsigned int start,unsigned int len) { const char *r; r = py_get_file_region(displayer,file,start,len); if (r) { /* fwrite(r,len,1,displayer->stream); */ pushback_n_chars(r, len, 1); } } /* ------------------------------------------- */ /* * By using constant gc lists it's possible to have regions, which * exceed input size. So we need to make a check */ void py_check_region(Displayer *displayer, int *start, int *len) { SGREPDATA(displayer); if ( *start>=displayer->last && (!displayer->start_warned) ) { sgrep_error(sgrep,"Warning: region start point greater than input size detected\n"); displayer->start_warned=1; *len=0; return; } if (*start+*len>displayer->last && displayer->end_warned) { sgrep_error(sgrep,"Warning: region end point greater than input size detected\n"); displayer->end_warned=1; *len=displayer->last-*start; } } /* ------------------------------------------- */ /* * Locates and maps the correct file for given region start point * assumes start is correct */ int py_locate_file_num(Displayer *displayer, int start) { /* Checking the common case: if we already have the right file */ if (displayer->current_file>=0 && start>=flist_start(displayer->files,displayer->current_file) && startfiles,displayer->current_file)+ flist_length(displayer->files,displayer->current_file)) { return displayer->current_file; } else { /* Do the binsearch */ return flist_search(displayer->files,start); } } /* ------------------------------------------- */ const char * py_fetch_region(Displayer *d,Region *region, int *size) { int fnum; int start,len; const char *r; if (!region || region->start==-1) { *size=0; return NULL; } start=region->start; len=region->end-start+1; py_check_region(d,&start,&len); if (len<=0) { *size=0; region->start=region->end=-1; return NULL; } fnum = py_locate_file_num(d,region->start); start-=flist_start(d->files,fnum); if (start+len>flist_length(d->files,fnum)) { /* Region stretches across files: cut the length */ len=flist_length(d->files,fnum)-start; } region->start+=len; r = py_get_file_region(d,fnum,start,len); *size= (r)? len : 0; return r; } /* ------------------------------------------- */ /* * Shows a region which might reside in more than one file. This is done * by finding out the files, where region is and calling py_show_file_region */ void py_show_region(Displayer *displayer,int start,int len) { int fnum; py_check_region(displayer,&start,&len); if (len<=0) return; fnum = py_locate_file_num(displayer,start); assert(fnum>=0 && fnumfiles)); while(len>0) { int fstart,flen; fstart=start-flist_start(displayer->files,fnum); flen=flist_length(displayer->files,fnum)-fstart; if (flen>len) flen=len; py_show_file_region(displayer,fnum,fstart,flen); start+=flen; len-=flen; fnum++; } /* while */ } /* py_show_region */ /* ------------------------------------------- */ /* * Handles % commands in output_style string */ void py_expand(Displayer *displayer, int ch, Region r) { char buf[PYSGREP_BUFFLEN]; /* FIXME: using direct pointer instead of index (i) might be faster. */ int i=-1; displayer->last_char=0; switch (ch) { case 'f': if (r.start>=displayer->last) { pushback_chars(""); break; } if (i==-1) i=flist_search(displayer->files,r.start); if (i>=0) { const char *name=flist_name(displayer->files,i); if (name) { pushback_chars(name); } else { pushback_chars(""); break; } } else { sgrep_error(displayer->sgrep, "Could not find file for region (%d,%d)\n", r.start,r.end); } break; case 's': sprintf(buf, "%d",r.start+displayer->first_ind); pushback_chars(buf); sprintf(buf, "%d", r.start+displayer->first_ind); pushback_chars(buf); break; case 'e': sprintf(buf, "%d", r.end+displayer->first_ind); pushback_chars(buf); break; case 'l': sprintf(buf, "%d", r.end-r.start+1); pushback_chars(buf); break; case 'i': if (r.start>displayer->last) i=flist_files(displayer->files)-1; else if (i==-1) i=flist_search(displayer->files,r.start); sprintf(buf, "%d", r.start-flist_start(displayer->files,i)); pushback_chars(buf); break; case 'j': if (r.end>displayer->last) i=flist_files(displayer->files)-1; else if (i==-1) i=flist_search(displayer->files,r.end); sprintf(buf, "%d", r.end-flist_start(displayer->files,i)); pushback_chars(buf); break; case 'r': py_show_region(displayer,r.start,r.end-r.start+1); break; case 'n': sprintf(buf, "%d", displayer->region); pushback_chars(buf); break; case '%': pushback_char('%'); break; default: pushback_char('%'); pushback_char(ch); displayer->last_char=ch; break; } } /* py_expand */ /* ------------------------------------------- */ /* * Handles \ escapes in output_style string * Note: missing \000 - \377 */ void py_escape(Displayer *displayer,int ch) { displayer->last_char=0; switch (ch) { case 'n': pushback_char('\n'); displayer->last_char='\n'; break; case 't': pushback_char('\t'); break; case '\\': pushback_char('\\'); break; case '\"': pushback_char('\"'); break; case '\r': pushback_char('\r'); break; case '\f': pushback_char('\f'); break; case '\b': pushback_char('\b'); break; case '%': pushback_char('%'); break; } /* switch */ } /* py_escape */ /* ------------------------------------------- */ /* * Prints a gc list using output_style and given file list */ int py_display_gc_list(Displayer *displayer,RegionList *l) { ListIterator lp; Region r,p; int i; int ch; struct SgrepStruct *sgrep=displayer->sgrep; start_region_search(l,&lp); get_region(&lp,&r); if (r.start>0 && sgrep->print_all) { /* There is text before first region */ py_show_region(displayer,0,r.start); } if (r.start==-1 && sgrep->print_all) { /* There was no regions, but we are in filter mode */ py_show_region(displayer,0,displayer->last); } while ( r.start!=-1 ) { /* Do the output_style */ for(i=0;(ch=sgrep->output_style[i]);i++) { if ( (ch=='%' || ch=='\\') && sgrep->output_style[i+1] ) { if (ch=='%') { py_expand(displayer,sgrep->output_style[++i],r); } /* if */ if (ch=='\\') { py_escape(displayer,sgrep->output_style[++i]); } /* if */ } else { pushback_char(ch); displayer->last_char=ch; } /* if */ } /* for */ p=r; get_region(&lp,&r); if (r.start>0 && p.endprint_all) { /* There is text between two regions */ py_show_region(displayer,p.end+1,r.start-p.end-1); } displayer->region++; } if (r.start==-1 && sgrep->print_all && p.endlast) { /* There is text after last region */ py_show_region(displayer,p.end+1,displayer->last-p.end-1); } if (displayer->last_char!='\n' && sgrep->print_newline) { pushback_char('\n'); } /* if */ /* if ((!ferror(displayer->stream))) fflush(displayer->stream); if (ferror(displayer->stream)) { sgrep_error(sgrep,"Error writing output: %s\n",strerror(errno)); return SGREP_ERROR; } */ return SGREP_OK; } /* py_display_gc_list */ /* ------------------------------------------- */ void py_init_displayer( Displayer * displayer, SgrepData * sgrep, FileList *files ) { displayer->sgrep=sgrep; displayer->files=files; displayer->region=1; displayer->current_file=-1; displayer->last=flist_total(files); displayer->first_ind=0; displayer->last_char=0; displayer->start_warned=0; displayer->end_warned=0; displayer->stream=NULL; displayer->map=NULL; displayer->map_size=0; } /* py_init_displayer */ /* ------------------------------------------- */ void py_clean_up_displayer(Displayer *displayer) { SGREPDATA(displayer); if (displayer->map!=NULL) { unmap_file(sgrep,displayer->map,displayer->map_size); } /* if */ } /* py_clean_up_displayer */ /* ------------------------------------------- */ Displayer * py_new_displayer(SgrepData *sgrep, FileList *files) { Displayer *d=sgrep_new(Displayer); py_init_displayer(d,sgrep,files); return d; } /* ------------------------------------------- */ void py_delete_displayer(Displayer *d) { SGREPDATA(d); py_clean_up_displayer(d); sgrep_free(d); } /* ------------------------------------------- */ int py_write_region_list( struct SgrepStruct *sgrep, RegionList * list, FileList * files ) { int r; Displayer displayer; py_init_displayer(&displayer,sgrep,files); py_clean_up_displayer(&displayer); r = py_display_gc_list(&displayer,list); return r; } /* ------------------------------------------- */