/*=============================================================================
GNU UnRTF, a command-line program to convert RTF documents to other formats.
Copyright (C) 2000,2001,2004 by Zachary Smith
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
The maintainer is reachable by electronic mail at daved@physiol.usyd.edu.au
=============================================================================*/
/*----------------------------------------------------------------------
* Module name: output
* Author name: Zachary Smith
* Create date: 18 Sep 01
* Purpose: Generalized output module
*----------------------------------------------------------------------
* Changes:
* 22 Sep 01, tuorfa@yahoo.com: addition of functions to change font size
* 22 Sep 01, tuorfa@yahoo.com: added function-level comment blocks
* 08 Oct 03, daved@physiol.usyd.edu.au: added stdlib.h for linux
* 25 Sep 04, st001906@hrz1.hrz.tu-darmstadt.de: added stdlib.h for djgpp
* 29 Mar 05, daved@physiol.usyd.edu.au: changes requested by ZT Smith
* 06 Jan 06, marcossamaral@terra.com.br: changes in STDOUT
* 16 Dec 07, daved@physiol.usyd.edu.au: updated to GPL v3
* 17 Dec 07, daved@physiol.usyd.edu.au: added support for --noremap from
* David Santinoli
* 09 Nov 08, arkadiusz.firus@gmail.com: use iconv
* 21 Aug 10, daved@physiol.usyd.edu.au: add code to deal with character
doublets (see convert.c)
*--------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "malloc.h"
#include "defs.h"
#include "error.h"
#include "output.h"
#include "main.h"
#include "convert.h"
#ifndef HAVE_ATTR_H
#include "attr.h"
#define HAVE_ATTR_H
#endif
/*========================================================================
* Name: op_create
* Purpose: Creates a blank output personality.
* Args: None.
* Returns: Output personality struct.
*=======================================================================*/
OutputPersonality*
op_create ()
{
OutputPersonality* new_op;
new_op = (OutputPersonality*) my_malloc (sizeof(OutputPersonality));
if (!new_op)
error_handler ("cannot allocate output personality");
memset ((void*) new_op, 0, sizeof (OutputPersonality));
return new_op;
}
/*========================================================================
* Name: op_free
* Purpose: Deallocates an output personality, but none of the strings
* it points to since they are usually constants.
* Args: OutputPersonality.
* Returns: None.
*=======================================================================*/
void
op_free (OutputPersonality *op)
{
CHECK_PARAM_NOT_NULL(op);
my_free ((void*) op);
}
/*========================================================================
* Name: op_translate_char
* Purpose: Performs a translation of a character in the context of
* a given output personality.
* Args: OutputPersonality, character set#, character.
* Returns: String.
*=======================================================================*/
char *
op_translate_char (OutputPersonality *op, my_iconv_t cd, int ch)
{
short start;
char *result=NULL;
static char output_buffer[2]={ 0, 0 };
char *inbuf, *outbuf;
size_t inbytes = (ch / 256) + 1, outbytes = inbytes * 4, i;
CHECK_PARAM_NOT_NULL(op);
if (no_remap_mode == TRUE && ch < 256)
{
output_buffer[0]=ch;
result=output_buffer;
}
else
if (result == NULL)
{
inbuf = my_malloc(inbytes + 1);
outbuf = my_malloc(outbytes + 1);
for (i = inbytes - 1; ch > 255; i--)
{
inbuf[i] = ch % 256;
ch /= 256;
}
inbuf[0] = ch;
inbuf[inbytes] = '\0';
i = outbytes;
if (!my_iconv_is_valid(cd))
{
cd = my_iconv_open("UTF-8", "cp1252");
if (my_iconv(cd, &inbuf, &inbytes, &outbuf, &outbytes) == -1)
{
#if 1 /* daved */
fprintf(stderr, "unrtf: Error in executing iconv1\n");
#else
fprintf(stderr, "unrtf: Error in executing iconv1\n");
#endif
return NULL;
}
my_iconv_close(cd);
}
else
if (my_iconv(cd, &inbuf, &inbytes, &outbuf, &outbytes) == -1)
{
fprintf(stderr, "unrtf: Error in executing iconv\n");
return NULL;
}
*outbuf = '\0';
outbuf -= i - outbytes;
/* Conversion from string to utf8 code number */
inbytes = 0;
for (i = 0; outbuf[i] != '\0'; i++)
inbytes++;
ch = 0;
for (i = 0; i < inbytes; i++)
{
if (i == 0)
switch (inbytes)
{
case 1:
ch = outbuf[0];
break;
case 2:
ch = (unsigned char) outbuf[0] - 192;
break;
case 3:
ch = (unsigned char) outbuf[0] - 224;
break;
case 4:
ch = (unsigned char) outbuf[0] - 240;
break;
}
else
ch = (ch * 64) + ((unsigned char) outbuf[i] - 128);
}
/* End of conversion*/
result = get_alias(op, ch);
if (result == NULL)
if (ch > 127 && op->unisymbol_print)
result = assemble_string(op->unisymbol_print, ch);
else
result = outbuf;
}
return result;
}
#if 0 /* daved - 0.21.2 */
/*========================================================================
* Name: op_translate_str
* Purpose: Performs a translation of a doublet the context of
* a given output personality.
* Args: OutputPersonality, character set#, character.
* Returns: String.
*=======================================================================*/
char *
op_translate_str (OutputPersonality *op, my_iconv_t cd, int * doublet)
{
short start;
char *result=NULL;
static char output_buffer[3]={ 0, 0, 0 };
unsigned char *inbuf;
char *outbuf;
int ch;
fprintf(stderr, "doublet = %o %o\n", *doublet, *(doublet+1));
#if 0
size_t inbytes = (ch / 256) + 1, outbytes = inbytes * 4, i;
#else
size_t inbytes = 3, outbytes = inbytes * 4, i;
#endif
CHECK_PARAM_NOT_NULL(op);
#if 0
if (no_remap_mode == TRUE && ch < 256)
{
output_buffer[0]=ch;
result=output_buffer;
}
else
if (result == NULL)
{
#endif
inbuf = (char *) my_malloc(inbytes + 1);
*inbuf = *doublet;
*(inbuf+1) = (unsigned char *) *(doublet+1);
*(inbuf+2) = 0;
fprintf(stderr, "inbuf = %o %o\n", *inbuf, *(inbuf+1));
outbuf = my_malloc(outbytes + 1);
#if 0
for (i = inbytes - 1; ch > 255; i--)
{
inbuf[i] = ch % 256;
ch /= 256;
}
inbuf[0] = ch;
inbuf[inbytes] = '\0';
#endif
i = outbytes;
if (!my_iconv_is_valid(cd))
{
cd = my_iconv_open("UTF-8", "cp1252");
if (my_iconv(cd, &inbuf, &inbytes, &outbuf, &outbytes) == -1)
{
fprintf(stderr, "unrtf: Error in executing iconv1\n");
return NULL;
}
my_iconv_close(cd);
}
else
{
if (my_iconv(cd, &inbuf, &inbytes, &outbuf, &outbytes) == -1)
{
#if 1 /* daved */
fprintf(stderr, "unrtf: Error in executing iconv - inbytes=%d inbuf[0]=%o inbuf[1]=%o\n", inbytes, inbuf[0], inbuf[1]);
#else
fprintf(stderr, "unrtf: Error in executing iconv\n");
#endif
return NULL;
}
}
*outbuf = '\0';
outbuf -= i - outbytes;
/* Conversion from string to utf8 code number */
inbytes = 0;
for (i = 0; outbuf[i] != '\0'; i++)
inbytes++;
ch = 0;
for (i = 0; i < inbytes; i++)
{
if (i == 0)
switch (inbytes)
{
case 1:
ch = outbuf[0];
break;
case 2:
ch = (unsigned char) outbuf[0] - 192;
break;
case 3:
ch = (unsigned char) outbuf[0] - 224;
break;
case 4:
ch = (unsigned char) outbuf[0] - 240;
break;
}
else
ch = (ch * 64) + ((unsigned char) outbuf[i] - 128);
}
/* End of conversion*/
result = get_alias(op, ch);
if (result == NULL)
if (ch > 127 && op->unisymbol_print)
result = assemble_string(op->unisymbol_print, ch);
else
result = outbuf;
#if 0 /* daved 0.21.2 */
}
#endif
return result;
}
#endif
#if 1 /* daved - 0.21.2 */
/*========================================================================
* Name: op_translate_doublet
* Purpose: Performs a translation of a doublet the context of
* a given output personality.
* Args: OutputPersonality, character set#, character byte 1 and 2
* Returns: String.
*=======================================================================*/
char *
op_translate_doublet (OutputPersonality *op, my_iconv_t cd, int ch1, int ch2)
{
short start;
char *result=NULL;
static char output_buffer[3]={ 0, 0, 0 };
unsigned char *inbuf;
char *outbuf;
int ch;
#if 0
size_t inbytes = (ch / 256) + 1, outbytes = inbytes * 4, i;
#else
size_t inbytes = 3, outbytes = inbytes * 4, i;
#if 0
fprintf(stderr, "doublet = %o %o\n", ch1, ch2);
#endif
#endif
CHECK_PARAM_NOT_NULL(op);
if (no_remap_mode == TRUE && ch < 256)
{
output_buffer[0]=ch1;
output_buffer[1]=ch2;
result=output_buffer;
}
else
if (result == NULL)
{
inbuf = (char *) my_malloc(inbytes + 1);
*inbuf = ch1;
*(inbuf+1) = ch2;
*(inbuf+2) = 0;
#if 0
fprintf(stderr, "inbuf = %o %o\n", *inbuf, *(inbuf+1));
#endif
outbuf = my_malloc(outbytes + 1);
i = outbytes;
if (!my_iconv_is_valid(cd))
{
cd = my_iconv_open("UTF-8", "cp1252");
if (my_iconv(cd, (char **)&inbuf, (size_t *)&inbytes, (char **)&outbuf, &outbytes) == -1)
{
fprintf(stderr, "unrtf: Error in executing iconv1\n");
return NULL;
}
my_iconv_close(cd);
}
else
{
if (my_iconv(cd, (char **)&inbuf, (size_t *)&inbytes, (char **)&outbuf, &outbytes) == -1)
{
#if 1 /* daved */
fprintf(stderr, "unrtf: Error in executing iconv - inbytes=%d inbuf[0]=%o inbuf[1]=%o\n", inbytes, inbuf[0], inbuf[1]);
#else
fprintf(stderr, "unrtf: Error in executing iconv\n");
#endif
return NULL;
}
}
*outbuf = '\0';
outbuf -= i - outbytes;
/* Conversion from string to utf8 code number */
inbytes = 0;
for (i = 0; outbuf[i] != '\0'; i++)
inbytes++;
ch = 0;
for (i = 0; i < inbytes; i++)
{
if (i == 0)
switch (inbytes)
{
case 1:
ch = outbuf[0];
break;
case 2:
ch = (unsigned char) outbuf[0] - 192;
break;
case 3:
ch = (unsigned char) outbuf[0] - 224;
break;
case 4:
ch = (unsigned char) outbuf[0] - 240;
break;
}
else
ch = (ch * 64) + ((unsigned char) outbuf[i] - 128);
}
/* End of conversion*/
result = get_alias(op, ch);
if (result == NULL)
if (ch > 127 && op->unisymbol_print)
result = assemble_string(op->unisymbol_print, ch);
else
result = outbuf;
}
return result;
}
#endif
/*========================================================================
* Name: op_begin_std_fontsize
* Purpose: Prints whatever is necessary to perform a change in the
* current font size.
* Args: OutputPersonality, desired size.
* Returns: None.
*=======================================================================*/
void
op_begin_std_fontsize (OutputPersonality *op, int size)
{
int found_std_expr = FALSE;
CHECK_PARAM_NOT_NULL(op);
/* Look for an exact match with a standard point size.
*/
switch (size) {
case 8:
if (op->fontsize8_begin) {
if (safe_printf(0, op->fontsize8_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize8_begin");
found_std_expr = TRUE;
}
break;
case 10:
if (op->fontsize10_begin) {
if (safe_printf(0, op->fontsize10_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize10_begin");
found_std_expr = TRUE;
}
break;
case 12:
if (op->fontsize12_begin) {
if (safe_printf(0, op->fontsize12_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize12_begin");
found_std_expr = TRUE;
}
break;
case 14:
if (op->fontsize14_begin) {
if (safe_printf(0, op->fontsize14_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize14_begin");
found_std_expr = TRUE;
}
break;
case 18:
if (op->fontsize18_begin) {
if (safe_printf(0, op->fontsize18_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize18_begin");
found_std_expr = TRUE;
}
break;
case 24:
if (op->fontsize24_begin) {
if (safe_printf(0, op->fontsize24_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize24_begin");
found_std_expr = TRUE;
}
break;
case 36:
if (op->fontsize36_begin) {
if (safe_printf(0, op->fontsize36_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize36_begin");
found_std_expr = TRUE;
}
break;
case 48:
if (op->fontsize48_begin) {
if (safe_printf(0, op->fontsize48_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize48_begin");
found_std_expr = TRUE;
}
break;
}
/* If no exact match, try to write out a change to the
* exact point size.
*/
if (!found_std_expr) {
if (op->fontsize_begin) {
char expr[16];
sprintf (expr, "%d", size);
if (safe_printf (1, op->fontsize_begin, expr)) fprintf(stderr, TOO_MANY_ARGS, "fontsize_begin");
} else {
/* If we cannot write out a change for the exact
* point size, we must approximate to a standard
* size.
*/
if (size<9 && op->fontsize8_begin) {
if (safe_printf(0, op->fontsize8_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize8_begin");
} else
if (size<11 && op->fontsize10_begin) {
if (safe_printf(0, op->fontsize10_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize10_begin");
} else
if (size<13 && op->fontsize12_begin) {
if (safe_printf(0, op->fontsize12_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize12_begin");
} else
if (size<16 && op->fontsize14_begin) {
if (safe_printf(0, op->fontsize14_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize14_begin");
} else
if (size<21 && op->fontsize18_begin) {
if (safe_printf(0, op->fontsize18_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize18_begin");
} else
if (size<30 && op->fontsize24_begin) {
if (safe_printf(0, op->fontsize24_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize24_begin");
} else
if (size<42 && op->fontsize36_begin) {
if (safe_printf(0, op->fontsize36_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize36_begin");
} else
if (size>40 && op->fontsize48_begin) {
if (safe_printf(0, op->fontsize48_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize48_begin");
} else
/* If we can't even produce a good approximation,
* just try to get a font size near 12 point.
*/
if (op->fontsize12_begin)
if (safe_printf(0, op->fontsize12_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize12_begin");
else
if (op->fontsize14_begin)
if (safe_printf(0, op->fontsize14_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize14_begin");
else
if (op->fontsize10_begin)
if (safe_printf(0, op->fontsize10_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize10_begin");
else
if (op->fontsize18_begin)
if (safe_printf(0, op->fontsize18_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize18_begin");
else
if (op->fontsize8_begin)
if (safe_printf(0, op->fontsize8_begin)) fprintf(stderr, TOO_MANY_ARGS, "fontsize8_begin");
else
error_handler ("output personality lacks sufficient font size change capability");
}
}
}
/*========================================================================
* Name: op_end_std_fontsize
* Purpose: Prints whatever is necessary to perform a change in the
* current font size.
* Args: OutputPersonality, desired size.
* Returns: None.
*=======================================================================*/
void
op_end_std_fontsize (OutputPersonality *op, int size)
{
int found_std_expr = FALSE;
CHECK_PARAM_NOT_NULL(op);
/* Look for an exact match with a standard point size.
*/
switch (size) {
case 8:
if (op->fontsize8_end) {
if (safe_printf(0, op->fontsize8_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize8_end");
found_std_expr = TRUE;
}
break;
case 10:
if (op->fontsize10_end) {
if (safe_printf(0, op->fontsize10_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize10_end");
found_std_expr = TRUE;
}
break;
case 12:
if (op->fontsize12_end) {
if (safe_printf(0, op->fontsize12_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize12_end");
found_std_expr = TRUE;
}
break;
case 14:
if (op->fontsize14_end) {
if (safe_printf(0, op->fontsize14_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize14_end");
found_std_expr = TRUE;
}
break;
case 18:
if (op->fontsize18_end) {
if (safe_printf(0, op->fontsize18_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize18_end");
found_std_expr = TRUE;
}
break;
case 24:
if (op->fontsize24_end) {
if (safe_printf(0, op->fontsize24_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize24_end");
found_std_expr = TRUE;
}
break;
case 36:
if (op->fontsize36_end) {
if (safe_printf(0, op->fontsize36_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize36_end");
found_std_expr = TRUE;
}
break;
case 48:
if (op->fontsize48_end) {
if (safe_printf(0, op->fontsize48_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize48_end");
found_std_expr = TRUE;
}
break;
}
/* If no exact match, try to write out a change to the
* exact point size.
*/
if (!found_std_expr) {
if (op->fontsize_end) {
char expr[16];
sprintf (expr, "%d", size);
if (safe_printf(1, op->fontsize_end, expr)) fprintf(stderr, TOO_MANY_ARGS, "fontsize_end");
} else {
/* If we cannot write out a change for the exact
* point size, we must approximate to a standard
* size.
*/
if (size<9 && op->fontsize8_end) {
if (safe_printf(0, op->fontsize8_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize8_end");
} else
if (size<11 && op->fontsize10_end) {
if (safe_printf(0, op->fontsize10_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize10_end");
} else
if (size<13 && op->fontsize12_end) {
if (safe_printf(0, op->fontsize12_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize12_end");
} else
if (size<16 && op->fontsize14_end) {
if (safe_printf(0, op->fontsize14_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize14_end");
} else
if (size<21 && op->fontsize18_end) {
if (safe_printf(0, op->fontsize18_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize18_end");
} else
if (size<30 && op->fontsize24_end) {
if (safe_printf(0, op->fontsize24_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize24_end");
} else
if (size<42 && op->fontsize36_end) {
if (safe_printf(0, op->fontsize36_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize36_end");
} else
if (size>40 && op->fontsize48_end) {
if (safe_printf(0, op->fontsize48_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize48_end");
} else
/* If we can't even produce a good approximation,
* just try to get a font size near 12 point.
*/
if (op->fontsize12_end)
if (safe_printf(0, op->fontsize12_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize12_end");
else
if (op->fontsize14_end)
if (safe_printf(0, op->fontsize14_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize14_end");
else
if (op->fontsize10_end)
if (safe_printf(0, op->fontsize10_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize10_end");
else
if (op->fontsize18_end)
if (safe_printf(0, op->fontsize18_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize18_end");
else
if (op->fontsize8_end)
if (safe_printf(0, op->fontsize8_end)) fprintf(stderr, TOO_MANY_ARGS, "fontsize8_end");
else
error_handler ("output personality lacks sufficient font size change capability");
}
}
}
#if 1 /* AK3 - AF */
/*========================================================================
* Name: add_alias
* Purpose: Adds alias (text) for a char number nr.
* Args: OutputPersonality, char's number, alias.
* Returns: None.
*=======================================================================*/
void
add_alias(OutputPersonality *op, int nr, char *text)
{
op->aliases = (Aliases *)add_to_collection((Collection *)op->aliases, nr, text);
}
/*========================================================================
* Name: get_alias
* Purpose: Search for alias for character number nr.
* Args: OutputPersonality, char's number.
* Returns: Text alias or NULL if found nothing.
*=======================================================================*/
char *
get_alias(OutputPersonality *op, int nr)
{
return get_from_collection((Collection *)op->aliases, nr);
}
#endif