`co(4,7);────────────────────────── /// Print Support ───────────────────────────────`co();

                               `keyword(Introduction,/// Introduction);
                           `keyword(Key Structure Elements,/// Key Structure Elements);

┌──────────────────────────────────────────────────────────────────────────┐	
│               `keyword(init_printer,/// init_printer);                `keyword(end_printer,/// end_printer);                    │
│               `keyword(print_char,/// print_char);                  `keyword(print_data,/// print_data);                     │
│               `keyword(print_eol,/// print_eol);                   `keyword(print_file,/// print_file);                     │
│               `keyword(print_screen,/// print_screen);                `keyword(print_str,/// print_str);                      │
│               `keyword(print_window,/// print_window);                `keyword(realloc_printer,/// realloc_printer);                │
│               `keyword(set_prt_xlat,/// set_prt_xlat);                `keyword(print_in_bkgrnd,/// print_in_bkgrnd);                │
└──────────────────────────────────────────────────────────────────────────┘

`color(RED,LIGHTGRAY);───────────────────────── /// Introduction ─────────────────────────────────`color();

  These routines are primarily designed for printing to a PRINTER.       
  However, any DOS file/device can be "printed" to. (com1,lpt1,tmp.dat,etc)
  The queuing routines are unique in the fact that the can "dynamically" 
  reallocate themselves and "grow" and "shrink" on the fly without losing
  a single byte of data.  The reallocation routines take advantage of the
  lightning fast movmem, as much out of convenience as speed.  An 8Mhz   
  286 can que 25,000 bytes worth of text strings, reallocating every     
  2048 bytes in ~1 second; really quite remarkable.                      
  The output is also quite fast if the "block mode" is taken advantage   
  of.  Even when block mode is not used, and a "write" occurs every byte,
  ~1024 bytes can be "printed" per second on the same machine.  Not many 
  printers can keep up with this!  This is sped up in block mode by      
  writing up to 512 bytes at a time.  This is not done by default since  
  outputting to a comm port at a slow baud rate may hamper performance,  
  especially if many bytes are written at once.                          
  As many as four print queues can be active and printing concurrently!

`color(RED,LIGHTGRAY);────────────────────── /// /// Key Structure Elements ─────────────────────────────`color();

  Several print structure elements are of importance.
    "halt" controls output from the queue.  If 1, output stops and the data
  in the queue remains unmodified.  If 0, output continues.
    "block_mode" controls the number of bytes output per call to the
  function "print_in_bkgnd".  If 0, only one byte per call will be output.
  This is useful for communication devices or printers.  If outputting to
  a file or laser printer, setting block mode to 1 will allow up to
  128 bytes to be output per call, thereby increasing performance.
    "xlat" and "xlat_flag" control printer translation.  See `keyword(set_prt_xlat,/// set_prt_xlat);
  for more details.  These variables can be modified directly if desired.

`co(10,1);/// init_printer`co();   `keyword(source,[UW_PRINT.C]~init_printer);
  This routine initializes a printer queue.  Printer queues can be either
  ram-based or disk-based. If ram-based, a queue can be no greater than 
  64k.  Disk-based queues can be up to 2 gigabytes. (Though we have never
  actually tried this!).  If disk-based, the initial and maximum size
  should be set to the same value, and a second filename is used as a
  disk buffer.  Be sure that the isize and msize values are "long".
  If any error occurs (file cannot be open, memory cannot be allocated,etc)
  a 0 will be returned.

Prototype:
int init_printer( char *fname, char *diskbuff,
  long isize, long msize, PRINT *p );

Parameters:
`co(11,1);	char  *fname`co();
		A pointer to a string containing the filename/device to print to.
`co(11,1);	char  *diskbuff`co();
		A pointer to a string containing the filename/device to use as a disk
    buffer.  This is NULL for ram-based queues.
`co(11,1);	long  isize`co();
		The initial size of the print queue. (Maximum 64k if ram based)
`co(11,1);	long  msize`co();
		The maximum size of the print queue. (Maximum 64k if ram based)
		isize and msize should be set equal if using a disk based queue.
`co(11,1);	PRINT *p`co();
    A pointer to a print queue structure.   

Usage:
	PRINT printer1, printer2;
	...
	if( !init_printer("out1.prt", NULL, 2048L, 16384L, &printer1) )
		wn_plst(0,0,"cannot initialize printer", wnp);
	if( !init_printer("out2.prt", "disk.buf", 32768L, 32768L, &printer2) )
		wn_plst(0,0,"cannot initialize printer", wnp);

`co(10,1);/// end_printer`co();   `keyword(source,[UW_PRINT.C]~end_printer);
  This routine closes any files and frees any memory used by the print
	queue.  If disk-based, the temporary disk file is left intact so that
	it will not have to be recreated during the next program execution.
	You may delete this file yourself if desired.

Prototype:
int end_printer( PRINT *p );

Parameters:
`co(11,1);	PRINT *p`co();
    A pointer to a print queue structure.   

Usage:
	PRINT printer1;
	...
	end_printer(&printer1);

`co(10,1);/// print_char`co();   `keyword(source,[UW_PRINT.C]~print_char);
  This routine prints a single character. A 0 is returned if an error occurs.

Prototype:
int print_char( uchar c, PRINT *p );

Parameters:
`co(11,1);	uchar c`co();
    A single byte to queue for printing.   
`co(11,1);	PRINT *p`co();
    A pointer to a print queue structure.   

Usage:
	PRINT printer1;
	...
	print_char('\r', &printer1);

`co(10,1);/// print_data`co();   `keyword(source,[UW_PRINT.C]~print_data);
  This routine prints a block of data. A 0 is returned if an error occurs.

Prototype:
int print_data( uchar *data, int cnt, PRINT *p );

Parameters:
`co(11,1);	uchar *data`co();
    A pointer to the data to queue for printing.   
`co(11,1);	int   cnt`co();
    The number of bytes to print.   
`co(11,1);	PRINT *p`co();
    A pointer to a print queue structure.   

Usage:
	uchar data[132];
	PRINT printer1;
	...
	print_data(data, 132, &printer1);

`co(10,1);/// print_eol`co();   `keyword(source,[UW_PRINT.C]~print_eol);
  This routine prints an end-of-line sequence. The print structure contains
  tow variables, "cr_cnt" and "lf_cnt" that control this sequence.  For
  every carriage return "cr_cnt", "lf_cnt" line feeds are output.  For
  instance, the simple case of cr_cnt = lf_cnt = 1 outputs \r\n  while
  cr_cnt = 1, lf_cnt = 2 outputs \r\n\n. A 0 is returned if an error occurs.

Prototype:
int print_eol( PRINT *p );

Parameters:
`co(11,1);	PRINT *p`co();
    A pointer to a print queue structure.   

Usage:
	PRINT printer1;
	...
	print_eol(&printer1);

`co(10,1);/// print_file`co();   `keyword(source,[UW_PRINT.C]~print_file);
  This routine prints an entire file.  The file is queued in "raw" format,
  no CR/LF translation occurs.  Make sure that there is enough room in the
  queue to hold the entire file.  A 0 is returned if an error occurs.

Prototype:
int print_file( char *fname, PRINT *p );

Parameters:
`co(11,1);	char  *fname`co();
		A pointer to a string containing the filename/device to print to.
`co(11,1);	PRINT *p`co();
    A pointer to a print queue structure.   

Usage:
	PRINT printer1;
	...
	print_file("uw_help6.hlp", &printer1);

`co(10,1);/// print_screen`co();   `keyword(source,[UW_PRINT.C]~print_screen);
  This routine prints the contents of the entire screen.  A 0 is returned if
	an error occurs.

Prototype:
int print_screen( PRINT *p );

Parameters:
`co(11,1);	PRINT *p`co();
    A pointer to a print queue structure.   

Usage:
	PRINT printer1;
	...
	print_screen(&printer1);

`co(10,1);/// print_str`co();   `keyword(source,[UW_PRINT.C]~print_str);
  This routine prints a single NULL terminated string. A 0 is returned if
	an error occurs.

Prototype:
int print_str( uchar *str, PRINT *p );

Parameters:
`co(11,1);	char  *str`co();
		A pointer to the string to print.
`co(11,1);	PRINT *p`co();
    A pointer to a print queue structure.   

Usage:
	PRINT printer1;
	...
	print_string("This is a print string", &printer1);

`co(10,1);/// print_window`co();   `keyword(source,[UW_PRINT.C]~print_window);
  This routine prints the contents of the current window.  If the window
	is bordered and the window parameter "inside" is 1, only the inside of
	the window is printed.  If "inside" is 0, the entire window, including
	the border is printed.  A 0 is returned if an error occurs.
  Note that this works even if the window is overlapped!

Prototype:
int print_window( WINDOW *wnp, PRINT *p );

Parameters:
`co(11,1);	WINDOW *wnp`co();
		A pointer to the window to print.
`co(11,1);	PRINT  *p`co();
    A pointer to a print queue structure.   

Usage:
	PRINT printer1;
	WINDOW wn;
	...
	print_window(&wn, &printer1);

`co(10,1);/// realloc_printer`co();   `keyword(source,[UW_PRINT.C]~realloc_printer);
  This routine is an internal routine and is used to "grow" and "shrink"
	ram-based printer queues dynamically.  A 0 is returned if an error occurs.

Prototype:
int realloc_printer( long new_size, PRINT *p );

Parameters:
`co(11,1);	long new_size`co();
		The new size, either greater or less than the current size.
`co(11,1);	PRINT  *p`co();
    A pointer to a print queue structure.   

Usage:
	PRINT printer1;
	...
	realloc_printer(32000L, &printer1);

`co(10,1);/// set_prt_xlat`co();   `keyword(source,[UW_PRINT.C]~set_prt_xlat);
  This routine allows translation of the data to occur.  For instance, the
	ASCII data queued can be printed as EBCDIC by pointing this to the
  appropriate table.  Another example would be to point to a table that
  contained ASCII equivalents to the IBM extended characters, thereby
  providing support for older printers that do not support them.
  Note that the translation occurs during output, not during the queueing
  process.

Prototype:
void set_prt_xlat( int state, uchar *xlat, PRINT *p );

Parameters:
`co(11,1);	int   state`co();
		If 1, the translation table is activated, if 0 it is deactivated.
`co(11,1);	uchar *xlat`co();
		A pointer to the translation table.
`co(11,1);	PRINT  *p`co();
    A pointer to a print queue structure.   

Usage:
	uchar xlat[256];
	PRINT printer1;
	...
	set_prt_xlat(1, xlat, &printer1);

`co(10,1);/// print_in_bkgrnd`co();   `keyword(source,[UW_PRINT.C]~print_in_bkgrnd);
  This routine is the "heart" of the printer routines.  It actually scans
	the printer queues and outputs the data to the appropriate file/device.
  You can call this routine as often and as fast as you see fit, or let
  the idle function call it in the "background".  There are no requirements
  as to when or how often this routine is called, but the more frequent
  the better the printer performance.  The total number of bytes output
  is returned.

Prototype:
int print_in_bkgrnd( void );

Parameters:

Usage:
	...
	while( !kbhit() )
		print_in_bkgrnd();
OR
	set_idle_func(print_in_bkgrnd);				/* wait event will call this for us */
	do{
			...
  }while(!end);

`co(4,7);─────────────────────── /// Timer/Sound Support ────────────────────────────`co();

  UltraWin V2.0 has the additional capability of "taking over" the PC timer
  interrupt.  It does this in a friendly manner by calling the old timer
  vector at the proper rate.  However, it is `co(15,?);very important`co(); to remember
  to call the function `co(11,1);end_video()`co(); before exiting your program or
  you may experience strange "crashes".  In addition, UltraWin increased
  the timer interrupt rate by a factor of 5, or approximately 91 ticks per
  second.  This allows you much finer control over your programs.  We also
  provide you with an easy to use timer facility for taking advantage of
  these features.  UltraWin also allows you to sound the PC speaker at a
  given frequency for a certain amount of time and the timer interrupt will
  turn the speaker off for you.

  The function `co(11,1);end_video()`co(); calls `co(11,1);end_clock()`co(); to restore the vector and
  clock rate if you forget to make the call. Taking over the PC timer will
  not affect the PC clock as the original interrupt is still called 18.2
  times per second.  However, if your program or another program that 
  controls your program also takes over the clock and changes the rate you
  may experience some problems.  If this is the case, simply do not call
  `co(11,1);init_clock()`co();.  You will not be able to use the timer variables or
  call `co(11,1);tone()`co(); but `co(11,1);wait_ticks()`co(); will still operate normally.
  
  There are 4 seperate countdown timers available for use in your programs.
  These are simply global variables that are decremented to 0 by the timer
  interrupt.  For instance, to delay for 1 second, say `co(11,1);Uw_timers[0] = 91;`co();
  You can then poll this variable at your convenience to determine the time
  expired.  The interrupt decrements the variable by 1 on each tic until
  the count reaches 0, at which time it will remain 0.  The global variables
  `co(11,1);Sys_timers`co(); and `co(11,1);Sound_timer`co(); should not be accessed as these are
  used by UltraWin and its sister product InTUItion.
  
`co(10,1);/// init_clock`co();   `keyword(source,[UW_VID.C]~init_clock);
  This routine takes over the PC timer interrupt and sets the timer rate
	to the desired value.                                              

Prototype:
void init_clock( int value );

Parameters:
`co(11,1);	uint  value`co();
    The countdown value for the PC timer chip.  0xffff is the standard
    18.2 times per second. 0x7fff would increase the rate by 2, etc.
    
Usage:
	...
 	init_clock(0x3333);												 /* speed up by factor of 5 */

`co(10,1);/// end_clock`co();   `keyword(source,[UW_VID.C]~end_clock);
  This routine restores the timer interrupt and rate.  Be sure to call this
  function before exiting your program.  `co(11,1);end_video()`co(); will call this for
  you if you forget.

Prototype:
void end_clock();

Parameters:

Usage:
	...
 	end_clock();
	end_mouse();
	end_video();
	exit(0);
  
`co(10,1);/// tone`co();   `keyword(source,[UW_VID.C]~tone);
  This routine sounds the PC speaker at the desired frequency for the 
	desired amount of time measured in timer tics. (91/s).  There is no
	need to turn the sound off, this is automatically handled by the timer
	interrupt.  It is perfectly safe to call tone even if a tone is already
	in progress.  The new frequency and time will override the current
	values.  If you need to turn the speaker off before the time has 
	expired you can call `co(11,1);sound_off();`co();

Prototype:
void tone( uint freq, int dur );

Parameters:
`co(11,1);	uint  freq`co();
    The desired frequency in hertz or cycles-per-second.   
`co(11,1);	int    dur`co();
    The duration of the tone in clock tics (91-per-second).

Usage:
	...
  if( error )
  	tone(1024,9);														 /* sound at 1k for 1/10 second */

`co(4,7);───────────────────── /// Ctrl-C/Ctrl-Break Control ────────────────────────`co();
  
  UltraWin V2.0 takes over the Ctrl-C and Ctrl-Break handlers and installs
  a dummy interrupt handler.  In this way, Ctrl-C can be used as any other
  control key.  More importantly, your program will not abort without 
  restoring the clock interrupt.  If you need further control over these
  handlers you can modify the ISR's `co(11,1);uw_ctrl_brk();`co(); and `co(11,1);uw_ctrl_c()`co();.
  
`co(4,7);─ End ──────────────────────────────────────────────────────────────────────`co();`sound(1024,10);
