/* xyz */

/*
 * Copyright (c) 1991-2005 by Wayne C. Gramlich.
 * All rights reserved.
 */

/*
 * This file implements the out_stream type operations in ANSI-C.
 */

#ifndef ERROR_EXPORTS_H
#include "error_exports.h"
#endif

#ifndef MEMORY_H
#include "memory.h"
#endif

#ifndef PORT_H
#include "port.h"
#endif

#ifndef STR_EXPORTS_H
#include "str_exports.h"
#endif

#ifndef UNIX_STDIO_H
#include "unix_stdio.h"
#endif

typedef void *String;
typedef struct out_stream_struct Out_stream_struct, *Out_stream;

struct out_stream_struct {
	String		file_name;	/* File name */
	Stdio		out_file;	/* Output file */
	int		is_open;	/* 1 => file is open */
	int		no_close;	/* 1 => Don't ever close */
};

extern void		logical__print(int, Out_stream);
extern void		string__put(String, Out_stream);
extern void		string__print(String, Out_stream);
extern String		string__read_only_copy(String);
extern Str		string__unix_string(String);

Out_stream_struct out_stream___initial_value;
Out_stream out_stream___initial = &out_stream___initial_value;
Out_stream_struct out_stream___standard_value;
Out_stream out_stream__standard = &out_stream___standard_value;
Out_stream_struct out_stream___error_value;
Out_stream out_stream__error = &out_stream___error_value;

/*
 * out_stream__external__initailize()
 *	This routine will initialize the initial, standard output, and 
 *	standard error out_stream objects.
 */
void
out_stream__external__initialize(void)
{
	Out_stream	out_stream;

	/* Create initial object: */
	out_stream = &out_stream___initial_value;
	out_stream->file_name = (String)"\024<initial out_stream>";
	out_stream->out_file = fopen("/dev/null", "w");
	out_stream->is_open = 0;
	out_stream->no_close = 1;
	out_stream___initial = out_stream;

	/* Create standard output: */
	out_stream = &out_stream___standard_value;
	out_stream->file_name = (String)"\021<standard output>";
	out_stream->out_file = stdout;
	out_stream->is_open = 1;
	out_stream->no_close = 1;
	out_stream__standard = out_stream;

	/* Create standard error: */
	out_stream = &out_stream___error_value;
	out_stream->file_name = (String)"\020<standard error>";
	out_stream->out_file = stderr;
	out_stream->is_open = 1;
	out_stream->no_close = 1;
	out_stream__error = out_stream;
}

/*
 * out_stream__address_get(out_stream)
 *	This routine will return the address of "out_stream".
 */
unsigned
out_stream__address_get(
	Out_stream	out_stream)
{
	return (unsigned)out_stream;
}

/*
 * out_stream__chracter_put(out_stream, character)
 *	This routine will output "character" to "out_stream".
 */
void
out_stream__character_put(
	Out_stream	out_stream,
	unsigned	character)
{
	(void)putc(character, out_stream->out_file);
}

/*
 * out_stream__close(out_stream)
 *	This routine will close "out_stream" if approprate.
 */
void
out_stream__close(
	Out_stream	out_stream)
{
	if (!out_stream->no_close) {
		(void)fclose(out_stream->out_file);
		out_stream->out_file = out_stream___initial->out_file;
		out_stream->is_open = 0;
		out_stream->no_close = 1;
	}
}

/*
 * out_stream__descriptor_open(descriptor)
 *	This routine will open "discriptor" for writing.
 *	If the open fails, the initial object is returned.
 */
Out_stream
out_stream__descriptor_open(
	unsigned	descriptor)
{
	Stdio		out_file;
	Out_stream	out_stream;

	out_file = fdopen(descriptor, "w");
	if (out_file == (Stdio)0) {
		out_stream = out_stream___initial;
	} else {
		out_stream = memory_alloc(Out_stream);
		out_stream->file_name = "\012descriptor";
		out_stream->out_file = out_file;
		out_stream->is_open = 1;
		out_stream->no_close = 0;
	}
	return out_stream;
}

/*
 * out_stream__float_write(out_stream, float)
 *	This procedure will write "float" to "out_stream".
 */
void
out_stream__float_write(
	Out_stream	out_stream, 
	int		flt)
{
	float f;

	f = *((float *)&flt);
	(void)fprintf(out_stream->out_file, " %g.8 ", f);
}


/*
 * out_stream__file_name_get(out_stream)
 *	This routine will return the file name associated with "out_stream".
 */
String
out_stream__file_name_get(
	Out_stream	out_stream)
{
	return out_stream->file_name;
}

/*
 * out_stream__file_number_get(out_stream)
 *	This routine will return the file number associated with "out_stream"
 */
unsigned
out_stream__file_number_get(
	Out_stream	out_stream)
{
	return fileno(out_stream->out_file);
}

/*
 * out_stream__flush(out_stream)
 *	This routine will flush out the contents of "out_stream".
 */
void
out_stream__flush(
	Out_stream	out_stream)
{
	(void)fflush(out_stream->out_file);
}

/*
 * out_stream__is_open_gen(out_stream)
 *	This routine will return 1 if "out_stream" is open and 0 otherwise;
 */
int
out_stream__is_open_get(
	Out_stream	out_stream)
{
	return out_stream->is_open;
}

/*
 * out_stream__open_append(file_name)
 *	This routine will open "file_name" for appending.
 *	If the open fails, the initial object is returned.
 */
Out_stream
out_stream__open_append(
	String		file_name)
{
	Stdio		out_file;
	Out_stream	out_stream;
	Str		unix_file_name;

	file_name = string__read_only_copy(file_name);
	unix_file_name = string__unix_string(file_name);
	out_file = fopen(unix_file_name, "a");
	if (out_file == (Stdio)0) {
		out_stream = out_stream___initial;
	} else {
		out_stream = memory_alloc(Out_stream);
		out_stream->file_name = file_name;
		out_stream->out_file = out_file;
		out_stream->is_open = 1;
		out_stream->no_close = 0;
	}
	return out_stream;
}

/*
 * out_stream__open_create(file_name)
 *	This routine will create "file_name" for writing.
 *	If the open fails, the initial object is returned.
 */
Out_stream
out_stream__open_create(
	String		file_name)
{
	Stdio		out_file;
	Out_stream	out_stream;
	Str		unix_file_name;

	file_name = string__read_only_copy(file_name);
	unix_file_name = string__unix_string(file_name);
	out_file = fopen(unix_file_name, "w");
	if (out_file == (Stdio)0) {
		out_stream = out_stream___initial;
	} else {
		out_stream = memory_alloc(Out_stream);
		out_stream->file_name = file_name;
		out_stream->out_file = out_file;
		out_stream->is_open = 1;
		out_stream->no_close = 0;
	}
	return out_stream;
}

/*
 * out_stream__pipe_close(out_stream)
 *	This routine will close "out_stream" if approprate.
 */
void
out_stream__pipe_close(
	Out_stream	out_stream)
{
	if (!out_stream->no_close) {
		(void)pclose(out_stream->out_file);
		out_stream->out_file = out_stream___initial->out_file;
		out_stream->is_open = 0;
		out_stream->no_close = 1;
	}
}

/*
 * out_stream__pipe_open(command)
 *	This routine will create "file_name" for writing.
 *	If the open fails, the initial object is returned.
 */
Out_stream
out_stream__pipe_open(
	String		command)
{
	Stdio		out_file;
	Out_stream	out_stream;
	Str		unix_command;

	command = string__read_only_copy(command);
	unix_command = string__unix_string(command);
	out_file = popen(unix_command, "w");
	if (out_file == (Stdio)0) {
		out_stream = out_stream___initial;
	} else {
		out_stream = memory_alloc(Out_stream);
		out_stream->file_name = command;
		out_stream->out_file = out_file;
		out_stream->is_open = 1;
		out_stream->no_close = 0;
	}
	return out_stream;
}

/*
 * out_stream__print(out_stream, print_stream)
 *	This routine will print a human readable version of "out_stream"
 *	to "print_stream".
 */
void
out_stream__print(
	Out_stream	out_stream,
	Out_stream	print_stream)
{
	string__put((String)"\013{file_name=", print_stream);
	string__print(out_stream->file_name, print_stream);
	string__put((String)"\012, is_open=", print_stream);
	logical__print(out_stream->is_open, print_stream);
	string__put((String)"\001}", print_stream);
}

/*
 * out_stream__float_print(out_stream, number)
 *	This routine will output "number" to "out_stream" as a floating
 *	point number.
 */
void
out_stream__float_print(
	Out_stream	out_stream,
	int		number)
{
	float		num;

	num = *((float *)&number);
	(void)fprintf(out_stream->out_file, "%g", (double)num);
}

/*
 * out_stream__integer_print(out_stream, number)
 *	This routine will output "number" to "out_stream" as a signed number.
 */
void
out_stream__integer_print(
	Out_stream	out_stream,
	unsigned	number)
{
	(void)fprintf(out_stream->out_file, "%d", number);
}

/*
 * out_stream__real_print(out_stream, number)
 *	This routine will output "number" to "out_stream" as a real number.
 */
void
out_stream__real_print(
	Out_stream	out_stream,
	double		*number)
{
	(void)fprintf(out_stream->out_file, "%.5g", *number);
}

/*
 * out_stream_write(out_stream, buffer, size)
 *	This routine will write "size" bytes of "buffer" to "out_stream".
 *	The number of bytes successfully written is returned.
 */
int
out_stream_write(
	Out_stream	out_stream,
	void		*buffer,
	unsigned	size)
{
	int		result;

	result = fwrite(buffer, 1, size, out_stream->out_file);
	return result;
}

/*
 * out_stream__unsigned_print(out_stream, number, radix)
 *	This routine will output "number" to "out_stream" as a number
 *	in radix "radix".  The valid values for "radix" are 8, 10, and 16.
 */
void
out_stream__unsigned_print(
	Out_stream	out_stream,
	unsigned	number,
	unsigned	radix)
{
	Stdio		out_file;

	out_file = out_stream->out_file;
	switch (radix) {
	    case 8:
		(void)fprintf(out_file, "%o", number);
		break;
	    case 16:
		(void)fprintf(out_file, "0x%x", number);
		break;
	    default:
		(void)fprintf(out_file, "%u", number);
	}
}

