[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference taveng::bagels

Title:BAGELS and other things of Jewish interest
Notice:1.0 policy, 280.0 directory, 32.0 registration
Moderator:SMURF::FENSTER
Created:Mon Feb 03 1986
Last Modified:Thu Jun 05 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:1524
Total number of notes:18709

452.0. "Print formatter for mixed Hebrew-English text" by BOLT::MINOW (Je suis marxiste, tendance Groucho) Thu Apr 14 1988 17:17

Last fall, when I was studying Yiddish, I decided to modify microEmacs
to handle mixed Hebrew-English text.  I never got the code working
well enough (still on the back burner), but you might find the
enclosed useful.  It takes mixed Hebrew and English text and prints
it on a Panasonic (or, I think, Epson) printer.  The program is
written in C and should be straight-forward to get working and/or
adapt to your needs.  It is not "product-quality", so don't even
bother extracting it if you're not interested in programming.

	hebrew.h	common definitions
	hformat.c	the formatter itself
	hprint.c	print on Epson printers

Martin.

/* Store this as hebrew.h */
/*
 * These definitions are for testing only.
 */

#define LOAD_PRINTER		1
#define	ATARI_ST		0
#define ASCII_UPCASE_HEBREW	1
#define DEBUG			1

/*
 * Header file for Hebrew printer.
 * Definitions:
 *	ISO_HEBREW		Hebrew characters are as defined by
 *				ISO 8859-8 (ECMA 121)
 *	ASCII_7BIT_HEBREW	Hebrew characters are in the ASCII
 *				7-bit range (replacing 'a'-'z')
 *	ASCII_UPCASE_HEBREW	Hebrew characters are in the ASCII
 *				7-bit range (replacing 'A'-'Z')
 *	ATARI_HEBREW		Hebrew characters are as defined by
 *				the Atari ST (in the range 0xC2..0xDC)
 * Only one of the above should be defined.  ASCII_UPCASE_HEBREW is
 * intended for convenience in debugging.
 *
 * If ATARI_ST is defined and non-zero, output will be directed to
 * the Atari printer port.  This code will probably work for IBM
 * (compatibles) without too much hacking.
 * If ATARI_ST is zero, output will be piped to stdout.
 *
 * If LOAD_PRINTER is non-zero (default), the character set will be
 * loaded into the printer.
 */

#include	<ctype.h>

#ifndef	ISO_HEBREW
#define	ISO_HEBREW		0
#endif

#ifndef	ASCII_7BIT_HEBREW
#define	ASCII_7BIT_HEBREW	0
#endif

#ifndef	ASCII_UPCASE_HEBREW
#define	ASCII_UPCASE_HEBREW	0
#endif

#ifndef ATARI_HEBREW
#define	ATARI_HEBREW		0
#endif

#if (ISO_HEBREW | ASCII_7BIT_HEBREW | ASCII_UPCASE_HEBREW | ATARI_HEBREW) == 0
#ifdef	ST
#define	ATARI_HEBREW		1
#else
#define	ISO_HEBREW		1
#endif
#endif

#if (ISO_HEBREW + ASCII_7BIT_HEBREW + ASCII_UPCASE_HEBREW + ATARI_HEBREW) != 1
    << error, you must define a character set >>
#endif

#ifndef	ATARI_ST
#ifdef ST
#define	ATARI_ST	1
#else
#define	ATARI_ST	0
#endif
#endif

#ifndef LOAD_PRINTER
#define LOAD_PRINTER	1
#endif

#ifndef	DEBUG
#define	DEBUG		0
#endif

#define TRUE		1
#define FALSE		0
#define EOS		'\0'

#define DEF_WIDTH	80		/* Printer width		*/
#define MAX_COLUMNS	512		/* Maximum line width		*/
#define LEFT_TO_RIGHT	0		/* Must be zero			*/
#define RIGHT_TO_LEFT	1

#if ISO_HEBREW
#define	FIRST_HEBREW	0xE0
#endif
#if ASCII_7BIT_HEBREW
#define	FIRST_HEBREW	0x60
#endif
#if ASCII_UPCASE_HEBREW
#define FIRST_HEBREW	'@'
#endif
#if ATARI_HEBREW
#define	FIRST_HEBREW	0xC2
#endif

#if ATARI_HEBREW
#define	MAXCHAR		27		/* Normal Hebrew character set	*/
#else
#define MAXCHAR		32		/* My Yiddish hacks		*/
#endif

#define ISHEBREW(c)		(c >= first_hebrew && c <= last_hebrew)
extern int		first_hebrew;
extern int		last_hebrew;

/*
 * Define some character testers.  Note that the argument must not
 * have side-effects.
 */
#define	ISENGLISH(c)	(!ISHEBREW(c) && isalpha(c))
#define	ISPUNCT(c)	(!ISHEBREW(c) && ispunct(c))
#define	ISSPACE(c)	isspace(c)
#define	ISDIGIT(c)	isdigit(c)

/*
 * Definitions for the multi-directional Hebrew formatter.  The data is
 * stored in a doubly-linked list.  The head of the list, h_listhead,
 * identifies the start and end characters, while h_cursor identifies
 * the current cursor position.  Note that the structure doesn't care
 * which direction the list is displayed.  I.e., transversing the
 * h_next pointer always moves from the natural start of the line
 * towards the end of the line (right to left for Hebrew, left to
 * right for English).
 *
 * Note: some of this is only interesting for a display editor.
 *
 * To extract data from the list (assume English):
 *	column = 0;
 *	hp = h_listhead.h_next;
 *	while (column < ncol && hp != &h_listhead) {
 *	    line[column] = hp->h_char;
 *	    hp = hp->h_next;
 *	    ++column;
 *	}
 */

typedef struct hlist {
    struct hlist	*h_next;		/* Start->end pointer	*/
    struct hlist	*h_prev;		/* End->start pointer	*/
    unsigned char	h_char;			/* Current character	*/
    short		h_offset;		/* Dot offset in line	*/
} HLIST;


#ifndef vms
#define noshare
#endif

extern noshare HLIST	h_listhead;		/* List handle		*/
extern noshare HLIST	*h_cursor;		/* Current cursor	*/
extern noshare int	h_is_interpolation;	/* Funny cursor?	*/
extern noshare int	debug;

#ifdef ST
#define strchr		index		/* Berkeley brain damage	*/
#endif
extern char		*strchr();
#define streq(a, b)	(strcmp(a, b) == 0)

/* Store this as hformat.c */
/*
 * Generalized Hebrew formatter
 * Author:		Martin Minow
 *			minow%[email protected]
 * Version:		30-Mar-1988
 *
 *	Copyright 1987, 1988 by Martin Minow, Arlington MA 02134, USA.
 *	All rights reserved.
 *
 *	Permission to copy without fee all or part of this material is granted
 *	provided that the copies are not made or distributed for direct
 *	commercial advantage, the copyright notice and title of the publication
 *	and its date appear, and notice is given that copying is by permission
 *	of Martin Minow.  To copy otherwise, or to republish, requires a fee
 *	and/or specific permission.
 */
static char copyright[] =
  "Copyright 1987, 1988 by Martin Minow, Arlington MA 02134, USA.\
   All rights reserved,";

#include "hebrew.h"
#define NIL		((HLIST *) 0)

/*
 * This is the list handle.  It is known outside.
 * h_char is set to EOS to stop loops in _shiftspace().
 * h_offset will be set to the length of the line.
 */
noshare HLIST		h_listhead = { NIL, NIL, EOS, 0 };

/*
 * h_cursor is needed to properly display the cursor in mixed-text
 * lines.  It marks the position (in display space) of the last
 * character entered.
 */
noshare HLIST		*h_cursor;		/* -> current cursor	*/

/*
 * h_is_interpolation is TRUE if, when the line is formatted and the
 * cursor put at the logical end of the line, the display cursor
 * is not at the visual end of the line.
 */
noshare int		h_is_interpolation;

/*
 * The following are private to hformat.c
 */
noshare	HLIST		h_data[MAX_COLUMNS];	/* Formatted line here	*/
noshare int		h_freepointer;		/* Index into h_data[]	*/

/*
 * Format a (mixed-language) line 'size' bytes (columns) long.
 * The result is stored in a linked list in h_data[].  The start
 * and end of the list are accessed via h_listhead, while the
 * current dot is accessed through h_cursor.
 * The output line may contain fewer than MAX_COLUMNS bytes of information.
 */

#define	H_NORMAL	0			/* Hebrew...		*/
#define	H_INTERPOLATION	1
#define	E_NORMAL	2			/* English...		*/
#define	E_INTERPOLATION	3

h_format(source, size, isright)
register char		*source;		/* Data start		*/
int			size;			/* Size of input	*/
int			isright;		/* Right->left if TRUE	*/
{
	register HLIST		*hp;		/* -> current element	*/
	register char		*lp;		/* -> current input	*/
	char			*lpend;		/* -> end of input line	*/
	register int		state;		/* Conversion state	*/
	register int		c;		/* Current character	*/

	/*
	 * To simplify the control flow, a lot of the actual byte-banging
	 * is done by subroutines.  Thus, we globalize the input parameters
	 * so they're accessable to the data movers.
	 */
	h_freepointer = 0;			/* Free all data	*/
	h_listhead.h_prev = &h_listhead;	/* Empty the display	*/
	h_listhead.h_next = &h_listhead;	/* list.		*/
	h_listhead.h_offset = size;		/* Remember line size	*/
	h_cursor = &h_listhead;			/* Initial cursor	*/
	/*
	 * There are two independent algorithms: one for left->right
	 * text (English with a few Hebrew words scattered in) and
	 * one for right->left text (Hebrew with some English).  The
	 * two are not symmetrical because of the way numbers work
	 * inside Hebrew strings in predominantly English text.
	 * The following is preliminary, and knowingly incomplete.
	 * In the commentary, Hebrew will be written in upper-case.
	 *
	 * For Hebrew text, stuff Hebrew letters and punctuation
	 * right-to-left until you hit an English letter or digit.
	 * Then, stuff the English text left to right.  When you
	 * return to Hebrew, fixup any trailing punctuation and
	 * shift trailing spaces and continue with the Hebrew.
	 *
	 * For English text, stuff the English forwards on the line
	 * until you hit some Hebrew, then write the Hebrew backwards.
	 * Note: this algorithim doesn't handle numbers quite correctly:
	 * input:  abc DEF 123 GHI jkl
	 * result: abc IHG 123 FED jkl -- correct
	 * actual: abc FED 123 IHG jkl -- incorrect.
	 *
	 * Remember that the list always runs "front to back" in the
	 * primary direction.  I.e., for English, the first element
	 * in the list is displayed in column 0, but for Hebrew, the
	 * first element is displayed in column 79.
	 */
	lp = source;				/* -> current line pos.	*/
	lpend = lp + size;			/* -> end of line	*/
	state = (isright) ? H_NORMAL : E_NORMAL;
	while (lp < lpend) {
	    c = *lp & 0xFF;
#if DEBUG
	    if (debug) {
		printf("state %d: %02x '%c' %s\n",
		    state,
		    c,
		    isprint(c) ? c : '?',
		    ISHEBREW(c)		? "Hebrew"
		    : ISENGLISH(c)	? "English"
		    : ISPUNCT(c)	? "Punct"
		    : ISSPACE(c)	? "Space"
		    :			  "Other"

		);
	    }
#endif
	    /*
	     * Get a new list element.  Note: the semantic line may be
	     * longer than the display line.  However, because text goes
	     * in "both" directions, stuff at the semantic end of the line
	     * may still be visible.  This is handled (as it were) by
	     * stealing the last element.
	     */
	    if (h_freepointer < MAX_COLUMNS)
		hp = &h_data[h_freepointer++];
	    else {
		hp = h_listhead.h_prev;		/* Last element		*/
		h_listhead.h_prev = hp->h_prev;	/* Unlink it		*/
	    }
	    hp->h_char = c;
	    hp->h_offset = (int) (lp - source);
	    switch (state) {
	    case H_NORMAL:
		h_normal(hp);
		if (ISENGLISH(c))		/* Interpolation coming	*/
		    state = H_INTERPOLATION;
		break;				/* Get next character	*/

	    case H_INTERPOLATION:
		if (ISENGLISH(c)		/* Alphabet or digit	*/
		 || ISPUNCT(c)			/* or punctuation	*/
		 || ISSPACE(c)) {		/* or whitespace	*/
		    h_abnormal(hp);
		}
		else {				/* Back to Hebrew	*/
		    h_shiftspaces();
		    h_normal(hp);
		    state = H_NORMAL;
		}
		break;

	    case E_NORMAL:			/* Normal English	*/
		h_normal(hp);
		if (ISHEBREW(c))		/* Start of Hebrew	*/
		    state = E_INTERPOLATION;
		break;

	    case E_INTERPOLATION:
		if (ISHEBREW(c)			/* More Hebrew		*/
		      || ISPUNCT(c)		/* or punctuation	*/
		      || ISSPACE(c)) {		/* or whitespace	*/
		    h_abnormal(hp);
		}
		else {				/* Now back to English	*/
		    h_shiftspaces();
		    h_normal(hp);
		    state = E_NORMAL;
		}
		break;
	    }					/* State machine exit	*/
	    ++lp;
	}
	if (state == H_INTERPOLATION
	 || state == E_INTERPOLATION)
	    h_is_interpolation = h_shiftspaces();
	else {
	    h_is_interpolation = FALSE;
	}
}

/*
 * Normal output (for Hebrew in a Hebrew line or English in an English line).
 */

h_normal(hp)
register HLIST		*hp;
{
	hp->h_next = &h_listhead;		/* New -> end marker	*/
	hp->h_prev = h_listhead.h_prev;		/* New -> old end elem.	*/
	(h_listhead.h_prev)->h_next = hp;	/* Old end -> new	*/
	h_cursor = h_listhead.h_prev = hp;	/* End -> new elem.	*/
}

/*
 * Abnormal (interpolation): right-to-left for Hebrew text in an English
 * line or left-to-right for English text in a Hebrew line.
 */

h_abnormal(hp)
register HLIST		*hp;
{
	hp->h_next = h_cursor;			/* Insert at cursor	*/
	hp->h_prev = h_cursor->h_prev;		/* What's before cursor	*/
	(h_cursor->h_prev)->h_next = hp;	/* Earlier->new		*/
	h_cursor->h_prev = hp;			/* Old cursor->new	*/
	h_cursor = hp;				/* New cursor is here	*/
}

/*
 * This routine is called at the transition between an interpolation
 * and the main text.  It shifts spaces and trailing punctuation from
 * the end of the interpolation to the edge of the line (between the
 * interpolation and subsequent text).  For example, letting '_' represent
 * blanks and assuming a Hebrew line with interpolated English text:
 * Semantics: ABC_123_DEF
 * Display:   FED_123_CDA
 * Note that, when the 'D' was seen (the first Hebrew letter after the
 * interpolation, the string looks like:
 *	         123__CDA
 *	            ^----- move this to left of '1'
 * Note: the code cannot loop forever as there must be a non-blank
 * between h_cursor and the end of the line.
 *
 * h_shiftspaces() returns (TRUE) if it didn't move any spaces.
 * This is needed if the display formatting ended in an interpolation.
 * TRUE means that the line is still inside an interpolation.
 */

int
h_shiftspaces()
{
	register HLIST		*start;
	register HLIST		*end;
	register HLIST		*next;

	/*
	 * Note: we can't get here unless there is a normal letter
	 * towards the end of the display line.  Thus, the following
	 * cannot loop forever.
	 */
	start = end = h_cursor;
	while (ISSPACE(start->h_char))
	    start = start->h_next;
	while (ISPUNCT(start->h_char))
	    start = start->h_next;
	/*
	 * Start points to the last character in the interpolation.
	 */
	if (start == end)
	    return (TRUE);			/* Still interpolating	*/
	/*
	 * Now, start points at the first non-space:
	 *
	 * abc  .FED
	 *     ^ ^
	 *     | +-- start
	 *     +---- end
	 * First, unlink the piece we want to mess around with.
	 */
	(end->h_prev)->h_next = start;
	next = start->h_prev;
	start->h_prev = end->h_prev;
	/*
	 * Now: the line looks like "abc FED"
	 * Finally, reinsert the interpolation spaces backwards (i.e.
	 * in it's normal display order.
	 */
	do {
	    start = next;
	    next = next->h_prev;
	    h_normal(start);
	} while (start != end);
	/*
	 * As if by magic, the line now looks like "abc FED. "
	 */
	return (FALSE);				/* Cursor is normal	*/
}

/* Store this as hprint.c */
/*
 * Hebrew print formatter
 * Author:		Martin Minow
 *			minow%[email protected]
 * Version:		30-Mar-1988
 *
 *
 *	Copyright 1987, 1988 by Martin Minow, Arlington MA 02134, USA.
 *	All rights reserved.
 *
 *	Permission to copy without fee all or part of this material is granted
 *	provided that the copies are not made or distributed for direct
 *	commercial advantage, the copyright notice and title of the publication
 *	and its date appear, and notice is given that copying is by permission
 *	of Martin Minow.  To copy otherwise, or to republish, requires a fee
 *	and/or specific permission.
 */
static char copyright[] =
  "Copyright 1987, 1988 by Martin Minow, Arlington MA 02134, USA.\
   All rights reserved,";

/*
 * Download the Hebrew font into the (Panasonic KX-P1080i) printer.
 * One would hope that this would work for Epson and compatibles.
 * Then print from the argument list or stdin.
 *
 * The Panasonic printer doesn't like using control-character positions
 * (including DEL 7/15) for font replacement.
 *
 * Hprint [-options] [files]
 *
 * Options:
 *	-d		Debug (conditionally compiled)
 *	-n		Use "near letter quality mode"
 *	-h		Set initial direction of file to Hebrew (right->left)
 *	-e		Set initial direction of file to English (left->right)
 *	-w<width>	Printer line width (default = 80)
 *	-s<value>	First Hebrew letter (default set by compilation)
 *
 * Input text is entered in "chronological" (i.e. speaking) order.  The
 * program, (assuming it is correct) handles all text reversals.
 *
 * You can specify the direction of a text segment by adding a line
 * containing (exactly)
 *	*h
 * or	*e
 * to set the direction to "Hebrew" or "English" respectively.
 *
 * Note: Printer Switch 8 on the Panasonic must be OFF.  This may
 * be a bug in the printer.
 */

#ifdef _STDC_
#if _STDC_ != 0
#include <stddef.h>
#endif
#endif
#include <stdio.h>
#ifdef ST
#include <osbind.h>
#include <bios.h>
#endif
#include "hebrew.h"

#ifndef	EXIT_SUCCESS
#define	EXIT_SUCCESS	0
#define	EXIT_FAILURE	1
#endif

int		nlq_mode = FALSE;	/* TRUE if Near Letter Quality	*/
int		nhebrew;		/* How many to download		*/
int		first_hebrew = FIRST_HEBREW; /* First right-to-left	*/
int		last_hebrew;		/* Last right_to_left char.	*/
int		line_width = DEF_WIDTH;	/* Printer line width		*/
int		default_direction = RIGHT_TO_LEFT;
char		input[MAX_COLUMNS + 1];	/* Text read here		*/
char		output[MAX_COLUMNS + 1]; /* Printer line built here	*/
#if DEBUG
int		debug = FALSE;
#endif

/*
 * The "ISO" values are for ECMA-121 (8-bit Latin/Hebrew Alphabet)
 * It is being submitted to ISO for standardization.
 * Characters from FB to FF (15/11 to 15/15) are my Yiddish hacks.
 * Note that I don't handle a couple of charcters needed for Yiddish.
 * The Yiddish and Hebrew transliterations are slightly different.
 * Those marked with an asterisk are handled.
 *
 * * Pasakh alef       [a]  Aleph with an underbar
 * * Komets alef       [o]  Aleph with a Komets (small 't') diacritic
 *   Melpum vov        [u]  Dotted Vav
 *   Khirik Yud        [i]  Yud with a dot underneath
 * * Pasakh tsvey yudn [ay] Two Yud with a joining underbar.
 * * Beyz              [b]  Dotted Bet
 *   Kof               [k]  Dotted Koph
 * * Pey               [p]  Dotted Fey
 *   Tof               [t]  Dotted Sof
 */

#if ISO_HEBREW || ASCII_7BIT_HEBREW || ASCII_UPCASE_HEBREW
char		charset[MAXCHAR][9] = {
/*  0     1     2     3     4     5     6     7     8		    ISO	*/
 0x00, 0x4E, 0x30, 0x00, 0x18, 0x00, 0x0C, 0x72, 0x00,	/* Aleph     E0 */
 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x7E, 0x00, 0x02,	/* Bet/Veyz  E1	*/
 0x00, 0x00, 0x46, 0x08, 0x50, 0x00, 0x7E, 0x00, 0x00,	/* Gimel     E2	*/
 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x7E, 0x00, 0x40,	/* Dalet     E3	*/
 0x4E, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x7E,	/* He	     E4	*/	
 0x00, 0x00, 0x00, 0x40, 0x00, 0x7E, 0x00, 0x00, 0x00,	/* Vav	     E5 */
 0x00, 0x00, 0x00, 0x40, 0x30, 0x4E, 0x00, 0x00, 0x00,	/* Zain	     E6 */
 0x7E, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x7E,	/* Het	     E7 */
 0x7E, 0x00, 0x02, 0x00, 0x02, 0x30, 0x42, 0x00, 0x7E,	/* Tet	     E8 */
 0x00, 0x00, 0x00, 0x40, 0x00, 0x70, 0x00, 0x00, 0x00,	/* Yod	     E9	*/
 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x7F,	/* Term Koph EA	*/
 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x7E,	/* Koph	     EB	*/
 0x00, 0xC0, 0x00, 0x42, 0x00, 0x44, 0x08, 0x70, 0x00,	/* Lamed     EC	*/
 0x7E, 0x00, 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x7E,	/* Term Mem  ED	*/
 0x00, 0x66, 0x18, 0x20, 0x40, 0x00, 0x42, 0x00, 0x7E,	/* Mem	     EE	*/
 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x7F, 0x00, 0x00,	/* Term Nun  EF	*/
 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x7E, 0x00, 0x00,	/* Nun	     F0	*/
 0x00, 0x7C, 0x02, 0x40, 0x02, 0x40, 0x02, 0x44, 0x38,	/* Samech    F1 */
 0x02, 0x00, 0x7E, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7E,	/* Ayin	     F2 */
 0x70, 0x00, 0x50, 0x00, 0x40, 0x00, 0x40, 0x00, 0x7F,	/* Term Pe   F3	*/
 0x72, 0x00, 0x52, 0x00, 0x42, 0x00, 0x42, 0x00, 0x7E,	/* Pe/Fey    F4	*/
 0x00, 0x7F, 0x00, 0x08, 0x00, 0x10, 0x20, 0x40, 0x00,	/* Term Sade F5	*/
 0x00, 0x62, 0x10, 0x0A, 0x00, 0x12, 0x28, 0x46, 0x00,	/* Zade	     F6	*/
 0x00, 0x40, 0x1E, 0x40, 0x00, 0x44, 0x08, 0x70, 0x00,	/* Koph	     F7	*/
 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x3E, 0x00,	/* Resh	     F8	*/
 0x7E, 0x00, 0x0A, 0x10, 0x62, 0x00, 0x02, 0x00, 0x7E,	/* Shin	     F9	*/
 0x02, 0x00, 0x7E, 0x00, 0x40, 0x00, 0x40, 0x00, 0x7E,	/* Taw	     FA	*/
 0x00, 0x4E, 0x30, 0x01, 0x18, 0x01, 0x0C, 0x72, 0x00,	/* Pasach Al FB */
 0x00, 0x4E, 0x30, 0x02, 0x19, 0x02, 0x0C, 0x72, 0x00,	/* Kometz Al FC */
 0x42, 0x10, 0x42, 0x10, 0x42, 0x00, 0x7E, 0x00, 0x02,	/* Beyz      FD	*/
 0x00, 0x40, 0x01, 0x70, 0x01, 0x00, 0x41, 0x00, 0x71,	/* Pas 2 yud FE	*/
 0x72, 0x00, 0x52, 0x08, 0x42, 0x08, 0x42, 0x00, 0x7E	/* Pe	     FF	*/
/*  0     1     2     3     4     5     6     7     8		    ISO	*/
};
#endif
#if ATARI_HEBREW
char		charset[MAXCHAR][9] = {
/*  0     1     2     3     4     5     6     7     8		  Atari	*/
 0x00, 0x4E, 0x30, 0x00, 0x18, 0x00, 0x0C, 0x72, 0x00,	/* Aleph     C2 */
 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x7E, 0x00, 0x02,	/* Bet/Veyz  C3	*/
 0x00, 0x00, 0x46, 0x08, 0x50, 0x00, 0x7E, 0x00, 0x00,	/* Gimel     C4	*/
 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x7E, 0x00, 0x40,	/* Dalet     C5	*/
 0x4E, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x7E,	/* He	     C6	*/	
 0x00, 0x00, 0x00, 0x40, 0x00, 0x7E, 0x00, 0x00, 0x00,	/* Vav	     C7 */
 0x00, 0x00, 0x00, 0x40, 0x30, 0x4E, 0x00, 0x00, 0x00,	/* Zain	     C8 */
 0x7E, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x7E,	/* Het	     C9 */
 0x7E, 0x00, 0x02, 0x00, 0x02, 0x30, 0x42, 0x00, 0x7E,	/* Tet	     CA */
 0x00, 0x00, 0x00, 0x40, 0x00, 0x70, 0x00, 0x00, 0x00,	/* Yod	     CB	*/
 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x7E,	/* Koph	     CC	*/
 0x00, 0xC0, 0x00, 0x42, 0x00, 0x44, 0x08, 0x70, 0x00,	/* Lamed     CD	*/
 0x00, 0x66, 0x18, 0x20, 0x40, 0x00, 0x42, 0x00, 0x7E,	/* Mem	     CE	*/
 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x7E, 0x00, 0x00,	/* Nun	     CF	*/
 0x00, 0x7C, 0x02, 0x40, 0x02, 0x40, 0x02, 0x44, 0x38,	/* Samech    D0 */
 0x02, 0x00, 0x7E, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7E,	/* Ayin	     D1 */
 0x72, 0x00, 0x52, 0x00, 0x42, 0x00, 0x42, 0x00, 0x7E,	/* Pe/Fey    D2	*/
 0x00, 0x62, 0x10, 0x0A, 0x00, 0x12, 0x28, 0x46, 0x00,	/* Zade	     D3	*/
 0x00, 0x40, 0x1E, 0x40, 0x00, 0x44, 0x08, 0x70, 0x00,	/* Koph	     D4	*/
 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x3E, 0x00,	/* Resh	     D5	*/
 0x7E, 0x00, 0x0A, 0x10, 0x62, 0x00, 0x02, 0x00, 0x7E,	/* Shin	     D6	*/
 0x02, 0x00, 0x7E, 0x00, 0x40, 0x00, 0x40, 0x00, 0x7E,	/* Taw	     D7	*/
 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x7F, 0x00, 0x00,	/* Term Nun  D8	*/
 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x7F,	/* Term Koph D9	*/
 0x7E, 0x00, 0x42, 0x00, 0x42, 0x00, 0x42, 0x00, 0x7E,	/* Term Mem  DA	*/
 0x70, 0x00, 0x50, 0x00, 0x40, 0x00, 0x40, 0x00, 0x7F,	/* Term Pe   DB	*/
 0x00, 0x7F, 0x00, 0x08, 0x00, 0x10, 0x20, 0x40, 0x00,	/* Term Sade DC	*/
/*  0     1     2     3     4     5     6     7     8		  Atari	*/
};
#endif

char		acute[1][9] = {
 0x00, 0x00, 0x20, 0x40, 0xA0, 0x40, 0x80, 0x00, 0x00	/* Acute accent	*/
};

#if ATARI_ST
#define PUTPRN(c) Bconout(BC_PRT, (int) c)	/* Output to printer	*/
#else
#define PUTPRN(c) putchar(c)			/* Output to stdout	*/
#endif
#define DC1	0x11				/* Awaken printer	*/
#define ESC	0x1B

main(argc, argv)
int		argc;
char		*argv[];
{
	get_number_of_characters();
	argc = getoptions(argc, argv);
#if LOAD_PRINTER
	setup_printer();
#endif
	if (argc <= 1)
	    printfile(stdin);
	else {
	    while (argc > 1) {
		if (freopen(argv[1], "r", stdin) == NULL) {
		    perror(argv[1]);
		    exit(EXIT_FAILURE);
		}
		else {
		    printfile(stdin);
		}
		--argc;
		++argv;
	    }
	}
#if LOAD_PRINTER
	unsetup_printer();
#endif
	exit(EXIT_SUCCESS);
}


/*
 * Do the printing
 */
printfile(fp)
FILE		*fp;
{
	register char		*tp;
	int			old_mode;
	int			primary_direction;

	old_mode = letter_quality(nlq_mode);
	primary_direction = default_direction;
	while (fgets(input, sizeof input, fp) != NULL) {
	    if ((tp = strchr(input, '\n')) != NULL)
		*tp = EOS;			/* Erase newline	*/
	    if (streq(input, "*h"))
		primary_direction = RIGHT_TO_LEFT;
	    else if (streq(input, "*e"))
		primary_direction = LEFT_TO_RIGHT;
	    else {
	        printline(input, primary_direction);
	    }
	}
	letter_quality(old_mode);
}

printline(text, isright)
char		*text;			/* Remove the newline first	*/
int		isright;		/* Assumed line direction	*/
{
	register char		*op;
	register HLIST		*hp;
	register int		column;

	h_format(text, strlen(text), isright);
	/*
	 * Now, we have a formatted line.  Walk the list and generate
	 * a character string (with leading blanks if it's right->left).
	 */
	hp = h_listhead.h_next;
	column = 0;
	if (isright) {
	    /*
	     * Working from the right end of the output line, copy characters
	     * from the formatted list.  Then, fill the left end of the line
	     * with blanks.  When done, op points to the left edge of the
	     * display line.
	     */
	    op = output + sizeof output;
	    *--op = EOS;
	    while (op > output && hp != &h_listhead) {
		*--op = hp->h_char;
		hp = hp->h_next;
		column++;
	    }
	    while (column < line_width && op > output) {
		*--op = ' ';
		column++;
	    }
	}
	else {
	    /*
	     * Working from the left edge of the output line, copy characters
	     * from the formatted list.  Then, terminate the line.  When
	     * done, op is set to point to the start of the display line.
	     */
	    op = output;
	    while (op < &output[sizeof output] && hp != &h_listhead) {
		*op++ = hp->h_char;
		hp = hp->h_next;
		column++;
	    }
	    *op = EOS;
	    op = output;
	}
#if DEBUG
	if (debug)
	    printf("line(%d)\n%s\n", strlen(op), op);
#endif
#if ATARI_ST
	while (*op != EOS)
	    PUTPRN(*op++);
	PUTPRN('\r');
	PUTPRN('\n');
#else
	puts(op);
#endif
}

int
getoptions(argc, argv)
int		argc;
char		*argv[];
{
	register int		i;
	register int		j;
	register char		*ap;

	for (i = j = 1; i < argc; i++) {
	    ap = argv[i];
	    if (*ap == '-') {
		switch (*++ap) {
#if DEBUG
		case 'd':
		    ++debug;
		    break;
#endif

		case 'e':
		    default_direction = LEFT_TO_RIGHT;
		    break;

		case 'h':
		    default_direction = RIGHT_TO_LEFT;
		    break;

		case 'n':
		    nlq_mode = TRUE;
		    break;

		case 'w':
		    line_width = atoi(++ap);
		    if (line_width <= 0
		     || line_width >= sizeof (output)) {
			fprintf(stderr, "Bad line width (%s) %d, %d used\n",
				argv[i], line_width, DEF_WIDTH);
			line_width = DEF_WIDTH;
		    }
		    break;

		case 's':
		    first_hebrew = atoi(++ap);
		    if (first_hebrew < ' '
		     || (first_hebrew + nhebrew) > 255) {
			fprintf(stderr, "Bad Hebrew character range start %d,",
			    first_hebrew);
			fprintf(stderr, ", using %d\n", FIRST_HEBREW);
			first_hebrew = FIRST_HEBREW;
		    }
		    break;

		default:
		    fprintf(stderr, "Ignoring unknown option \"%s\"\n",
			    argv[i]);
		    break;
		}
		continue;
	    }
	    else {
		argv[j++] = ap;
	    }
	}
	argv[j] = NULL;
	return (j);
}

get_number_of_characters()
{
	register int		i;
	register char		*info;

	for (nhebrew = 0; nhebrew < MAXCHAR; nhebrew++) {
	    info = charset[nhebrew];
	    for (i = 0; i < 9; i++) {
		if (*info++ != 0)
		    goto next_char;
	    }
	    break;
next_char:  ;
	}
	last_hebrew = first_hebrew + nhebrew - 1;	/* Last valid	*/
}

#if LOAD_PRINTER
setup_printer()
{
	register int		i;

	reset_printer();
	PUTPRN(ESC);
	PUTPRN('m');				/* Select printer mode	*/
	PUTPRN('3');				/* IBM Printer Mode II	*/
	PUTPRN(ESC);				/* Configure for 8-bit	*/
	PUTPRN('#');				/* transparent mode.	*/
	for (i = 0; i < nhebrew; i++)
	    load_printer(i + first_hebrew, charset[i]);
#if ATARI_HEBREW
	load_printer(0xBA, &acute[0][0]);
#endif
#if ISO_HEBREW
	load_printer(0xB8, &acute[0][0]);
#endif
}

load_printer(c, info)
int		c;
register char	*info;
{
	register int		i;

	PUTPRN(ESC);				/* Download character	*/
	PUTPRN('y');				/* set it here		*/
	PUTPRN(c);				/* This character	*/
	for (i = 0; i < 9; i++)
	    PUTPRN(*info++);
}

unsetup_printer()
{
	register int		i;

	for (i = 0; i < nhebrew; i++) {
	    PUTPRN(ESC);			/* Download character	*/
	    PUTPRN('z');			/* remove it here	*/
	    PUTPRN(i + first_hebrew);
	}
	PUTPRN(ESC);
	PUTPRN('m');				/* Select Printer Mode	*/
	PUTPRN('0');				/* Standard Mode	*/
	reset_printer();
}
#endif


test()
{
	register int		i;
	int			old_mode;

	old_mode = letter_quality(nlq_mode);
	for (i = 0x20; i <= 0x7F; i++) {
	    if ((i % 32) == 0) {
		PUTPRN('\r');
		PUTPRN('\n');
	    }
	    PUTPRN(i);
	}
	PUTPRN('\r');
	PUTPRN('\n');
	letter_quality(old_mode);
}

int
letter_quality(new_mode)
int		new_mode;			/* TRUE for l.q. mode	*/
{
#if ATARI_ST
	static int	current_mode = FALSE;	/* draft/nlq mode	*/
	int		previous_mode = current_mode;

	PUTPRN(ESC);
	if (new_mode)
	    PUTPRN('n');			/* NLQ mode		*/
	else {
	    PUTPRN('P');			/* Draft mode		*/
	}
	current_mode = new_mode;
	return (previous_mode);
#else
	return (new_mode);
#endif
}

reset_printer()
{
	PUTPRN(DC1);				/* Awaken		*/
	PUTPRN(ESC);
	PUTPRN('@');
	PUTPRN(DC1);				/* Awaken again		*/
}

T.RTitleUserPersonal
Name
DateLines
452.1RAWFSH::MAHLERMichael | Digital Telecommunications EngineeringThu Apr 14 1988 17:296
    
    
    	You should have started before I was born....
    
    
    
452.2I have done the MicroEMACS procedureMPGS::ORNSTEINIan Ornstein Thu Apr 14 1988 18:3411
	I have written a �EMACS procedure to key Hebrew.

	I'll try to post it later tonight.  There is a small
	problem...unless you look at it on a screen that substitutes
	the Hebrew characters for the Greek ones, you will be quite
	confused ;-) Also, my substitutions are the ones for the
	I*M character set not the 7 bit compatable one that DEC uses.

						- Ian -

						
452.3ivrit.rcMPGS::ORNSTEINIan Ornstein Thu Apr 14 1988 22:34149
;
39	store-macro       
write-message "[Hebrew (�����) Mode Enabled]"
update-screen
set    %ivrit TRUE
!while %ivrit TRUE
        set %data &gtkey
  	!if &EQual &asc %data 7
    	    write-message "[English Mode Restored]"
            set %ivrit FALSE
	    !return
        !endif
    	!if &EQual &asc %data  13
                end-of-line
                newline
                next-line
        !endif
    	!if &EQual &asc %data  9
                handle-tab
        !endif
    	!if &SEQual %data     " "
		insert-string " "
		!goto backup
        !endif
    	!if &SEQual %data     "a"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "b"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "c"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "d"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "e"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "f"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "g"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "h"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "i"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "j"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "k"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "l"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "m"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "n"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "o"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "p"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "q"
		insert-string "/"
		!goto backup
        !endif
    	!if &SEQual %data     "r"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "s"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "t"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "u"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "v"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "w"
		insert-string "'"
		!goto backup
        !endif
    	!if &SEQual %data     "x"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "y"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "z"
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "."
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     ","
		insert-string "�"
		!goto backup
        !endif
    	!if &SEQual %data     "/"
		insert-string "."
		!goto backup
        !endif
    	!if &SEQual %data     ";"
		insert-string "�"
		!goto backup
        !endif
*backup
	backward-character
        update-screen          
!endwhile
!endm