/****************************************************************************** ** $Id: print.c,v 2.30 1997/12/06 18:57:08 gerd Exp $ **============================================================================= ** ** This file is part of BibTool. ** It is distributed under the GNU General Public License. ** See the file COPYING for details. ** ** (c) 1996-2004 Gerd Neugebauer ** ** Net: gene@gerd-neugebauer.de ** **----------------------------------------------------------------------------- ** Description: ** This module provides also access to the functions and ** variables defined in |entry.c|. Consult also the documentation ** of this file for details. ** ** ******************************************************************************/ #include #include #include #include #include #include #include #include #include /*****************************************************************************/ /* Internal Programs */ /*===========================================================================*/ #ifdef __STDC__ #define _ARG(A) A #else #define _ARG(A) () #endif char * sput_record _ARG((Record rec,DB db,Uchar *start));/* print.c */ static int fput_char _ARG((int c)); /* print.c */ static int sput_char _ARG((int c)); /* print.c */ static void indent _ARG((int col,int (*fct)_ARG((int))));/* print.c */ static void line_breaking _ARG((char *t,int align,int (*fct)_ARG((int))));/* print.c*/ static void print_equation _ARG((Uchar *pre,Uchar *s,Uchar *t,int align,int (*fct)_ARG((int))));/* print.c*/ static void puts_in _ARG((char *s,int in,int (*fct)_ARG((int))));/* print.c */ void fput_record _ARG((FILE *file,Record rec,DB db,Uchar *start));/* print.c*/ void put_record _ARG((int (*fct)_ARG((int)),Record rec,DB db,Uchar *start));/* print.c*/ void set_key_type _ARG((char * s)); /* print.c */ void set_symbol_type _ARG((char * s)); /* print.c */ /*****************************************************************************/ /* External Programs */ /*===========================================================================*/ /*---------------------------------------------------------------------------*/ #define TAB_WIDTH 8 static int symbol_type = SYMBOL_TYPE_LOWER; static char * s_upper = "upper"; static char * s_lower = "lower"; static char * s_cased = "cased"; /*----------------------------------------------------------------------------- ** Function: set_symbol_type() ** Purpose: Function to set the symbol type which is used by the ** printing routine. The argument is a string describing ** the value to use. Possible values are |"upper"|, ** |"lower"|, and |"cased"|. The comparison of the values ** is performed case insensitive. ** ** If no appropriate value is found then an error message ** is issued as the only action. ** ** This function is called from |rsc.c|. ** Arguments: ** s String description of the value. ** Returns: nothing **___________________________________________________ */ void set_symbol_type(s) /* */ register char * s; /* */ { if ( case_cmp(s,s_upper) ) /* */ { symbol_type = SYMBOL_TYPE_UPPER; } /* */ else if ( case_cmp(s,s_cased) ) /* */ { symbol_type = SYMBOL_TYPE_CASED; } /* */ else if ( case_cmp(s,s_lower) ) /* */ { symbol_type = SYMBOL_TYPE_LOWER; } /* */ else /* */ { Err("Unknown symbol type ignored.\n"); } /* */ } /*------------------------*/ #ifdef MAYBE_IN_THE_NEXT_RELEASE static int key_type = SYMBOL_TYPE_LOWER; /*----------------------------------------------------------------------------- ** Function*: set_key_type() ** Purpose: Wrapper function to set the static variable key_type. ** This function is called from rsc.c ** Arguments: ** s String description of the value. ** Returns: nothing **___________________________________________________ */ void set_key_type(s) /* */ register char * s; /* */ { if ( case_cmp(s,s_upper) ) /* */ { key_type = SYMBOL_TYPE_UPPER; } /* */ else if ( case_cmp(s,s_cased) ) /* */ { key_type = SYMBOL_TYPE_CASED; } /* */ else if ( case_cmp(s,s_lower) ) /* */ { key_type = SYMBOL_TYPE_LOWER; } /* */ else /* */ { Err("Unknown key type ignored.\n"); } /* */ } /*------------------------*/ #endif /*------------------------*/ static int column = 0; /* The current column of */ /* the output stream is */ /* kept in this variable.*/ #define NL (void)(*fct)('\n'),column=0 #define PUTC(C) (void)((*fct)(C),++column) #define PUTS(S) puts_in(S,0,fct) /*----------------------------------------------------------------------------- ** Function: puts_in() ** Purpose: Print a string and update current column. ** Arguments: ** s string to be printed. ** in indentation. Alignment column. ** fct function to use for writing a character. ** Returns: nothing **___________________________________________________ */ static void puts_in(s,in,fct) /* */ register char *s; /* */ register int in; /* */ int (*fct)_ARG((int)); /* */ { /* */ while ( *s ) /* */ { (void)(*fct)(*s); /* */ switch ( *(s++) ) /* */ { case '\t': /* */ column += TAB_WIDTH - (column%TAB_WIDTH); /* */ break; /* */ case '\n': /* */ column = 0; /* */ if ( in > 0 ) indent(in,fct); /* */ break; /* */ default: ++column; /* */ } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: indent() ** Purpose: Add spaces or tabs to indent to the given column. ** the current column is beyond col nothing happens. ** The resource use.tabs can be used to disable the use of TAB. ** Arguments: ** col Target column ** fct function to use for writing a character. ** Returns: nothing **___________________________________________________ */ static void indent(col,fct) /* */ register int col; /* */ int (*fct)_ARG((int)); /* */ { /* */ if ( col > rsc_linelen ) col = rsc_linelen; /* */ while ( column < col ) /* */ { if ( rsc_use_tabs /* TAB is allowed and */ && column+TAB_WIDTH-(column%TAB_WIDTH) <= col )/* enough space left */ { (void)(*fct)('\t'); /* then put a TAB and */ column += TAB_WIDTH - (column%TAB_WIDTH); /* update column. */ } /* */ else /* otherwise */ { (void)(*fct)(' '); /* write a singe space */ ++column; /* and advance column. */ } /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: line_breaking() ** Purpose: Write out a right hand side of an equation. ** If it does not fit break the line into several parts and ** print them on successive lines. ** Temporarily end marks are placed inside the string, ** but the old contents has been restored at the end. ** Arguments: ** t string to print. ** align starting column for continuation lines. ** fct function to use for writing a character. ** Returns: nothing **___________________________________________________ */ static void line_breaking(t,align,fct) /* */ register char *t; /* string to print. */ int align; /* alignment column */ int (*fct)_ARG((int)); /* */ { register char *s; /* intermediate pointer */ char end_c; /* temp. character. */ int brace, /* brace counter */ len, /* length of rem. output */ first = TRUE; /* indicator for # */ /* */ while ( is_space(*t) ) ++t; /* skip leading spaces */ /* */ indent(align,fct); /* goto alignment column */ /* */ while ( *t ) /* as long as sth to print*/ { s = t; /* */ /* */ switch( *t ) /* */ { case '"': /* QUOTED PART */ for ( len=2,++t; /* */ *t && *t != '\"'; /* Search terminating " */ ++t,++len ) /* */ { if ( *t == '\\' && *(t+1) != '\0' ) /* skip over quoted and */ { ++t; ++len; } /* similar constructs. */ } /* */ if ( *t ) ++t; /* skip after end, if poss*/ if ( *t ) { end_c = *++t; *t = '\0'; } /* save char and mark end.*/ else { end_c = *t; } /* */ break; /* */ case '{': /* BRACED PART */ brace = 1; /* */ for ( len=2,++t; /* find matching brace. */ *t && brace>0; /* */ ++t,++len ) /* */ { switch ( *t ) /* */ { case '\\': if ( *(t+1) ) ++t; break; /* ignore \{ \} etc */ case '{': ++brace; break; /* */ case '}': brace--; break; /* */ } /* */ } /* */ if ( *t ) { end_c = *++t; *t = '\0'; } /* save char and mark end.*/ else { end_c = *t; } /* */ break; /* */ default: /* Now we should have a */ while ( is_allowed(*t) ) ++t; /* SYMBOL */ end_c = *t; *t = '\0'; /* */ s = (char*)get_item(symbol(s),symbol_type);/* */ len = strlen(s); /* */ } /* */ /* Now s is a single */ /* string to print. */ /* t points to the closing*/ /* '\0' of s */ /* end_c is the old *t */ while ( *s ) /* */ { if ( len + (first?0:3) <= rsc_linelen - column)/* Is there enough space*/ { if ( !first ) PUTS(" # "); /* Maybe add separator */ puts_in(s,align,fct); /* write it out */ s = t; /* and we are done */ } /* */ else if ( !first ) /* If sth has been before */ { puts_in("\n# ",align-2,fct); /* start a new line */ first = TRUE; /* */ } /* Now we have to break */ else /* a single entry */ { char save_c, /* */ *save_ptr, /* */ *ptr; /* */ /* */ if ( 0 <= rsc_linelen - column ) /* */ save_ptr = s + rsc_linelen - column; /* Potential end */ else /* */ save_ptr = s; /* */ /* */ for(ptr=s; /* Search next newline */ ptr <= save_ptr && *ptr != '\n'; /* or end of region */ ptr++) {} /* */ /* */ if ( *ptr == '\n' ) /* */ { save_ptr = ptr; /* */ *save_ptr = '\0'; /* Save and mark end. */ puts_in(s,align,fct); /* */ NL; /* */ indent(align,fct); /* */ *save_ptr = '\n'; /* Restore end */ len += s - save_ptr - 1; /* Update the length */ s = save_ptr+1; /* */ } /* */ else /* */ { /* */ while ( save_ptr != s && *save_ptr != ' ' )/* */ { save_ptr--; } /* Find a SPC backward */ /* */ if ( save_ptr == s ) /* If no SPC found then */ { while ( *save_ptr && *save_ptr != ' ' )/* search one forward. */ { ++save_ptr; } /* */ } /* */ len += s - save_ptr; /* Update the length */ save_c = *save_ptr; *save_ptr = '\0'; /* Save and mark end. */ puts_in(s,align,fct); /* */ NL; /* */ indent(align,fct); /* */ *save_ptr = save_c; /* Restore end */ s = save_ptr; /* */ while ( is_space(*s) ) { ++s; len--; } /* Skip spaces */ } /* */ } /* */ } /* */ *t = end_c; /* Restore the end */ /* */ while ( *t && *t != '#' ) ++t; /* Search next # */ if ( *t ) ++t; /* Skip beyond the # */ while ( is_space(*t) ) ++t; /* Ignore following spaces*/ first = FALSE; /* */ } /* */ } /*------------------------*/ /*----------------------------------------------------------------------------- ** Function: print_equation() ** Purpose: Print something of the form s = t ** If desired it can be indented. t is broken if it doesn't fit ** in one line. ** Arguments: ** pre string to be printed before s. ** s left hand side ** t right hand side ** align target column. If negative no indentation is performed. ** fct function to use for writing a character. ** Returns: nothing **___________________________________________________' */ static void print_equation(pre,s,t,align,fct) /* */ Uchar *pre; /* */ Uchar *s; /* */ Uchar *t; /* */ int align; /* */ int (*fct)_ARG((int)); /* */ { /* */ if ( align < 0 ) /* */ { PUTS(pre); /* */ PUTS(get_item(s,symbol_type)); /* */ if ( rsc_print_we ) /* */ { PUTS(" = "); } /* */ else /* */ { PUTC('='); } /* */ PUTS(t); /* */ } /* */ else /* */ { indent(rsc_indent,fct); /* */ PUTS(pre); /* */ PUTS(get_item(s,symbol_type)); /* */ if ( column>=align-2 && rsc_print_we ) /* */ { PUTC(' '); } /* */ else if ( rsc_eq_right ) /* */ { indent(align-2,fct); } /* */ else if ( column0; i-=2 ) /* */ { /* No deleted or */ if ( *hp && is_allowed(**hp) ) /* private entry */ { /* */ if ( *(hp+1) ) /* If equation */ { PUTS(comma1); /* */ NL; /* */ print_equation(comma2, /* */ *hp, /* */ (rsc_expand_macros /* */ ? expand_rhs(*(hp+1),/* */ (rsc_braces?"{":"\""),/* */ (rsc_braces?"}":"\""),/* */ db) /* */ : *(hp+1) ), /* */ rsc_col, /* */ fct); /* */ } /* */ else /* Otherwise print a key */ { indent(rsc_col_key,fct); /* */ PUTS(get_key_name(*hp)); /* */ } /* */ } /* */ hp += 2; /* Goto next pair. */ } /* */ } /* */ NL; /* */ PUTC(close_brace); /* */ for ( i=rsc_newlines; i>0; --i ) { NL; } /* */ } /* */ } /*------------------------*/