1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 1995 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*      Copyright (c) 1984 AT&T */
28/*        All Rights Reserved   */
29
30#pragma ident	"%Z%%M%	%I%	%E% SMI"
31
32
33/*LINTLIBRARY*/
34/*
35 * This version writes directly to the buffer rather than looping on putc.
36 * Ptr args aren't checked for NULL because the program would be a
37 * catastrophic mess anyway.  Better to abort than just to return NULL.
38 */
39#include <stdio.h>
40#include "stdiom.h"
41#include <errno.h>
42#include <memory.h>
43
44static char	*memnulccpy(char *, char *, int, int);
45
46int
47fputs(char *ptr, FILE *iop)
48{
49	int ndone = 0, n;
50	unsigned char *cptr, *bufend;
51	char *p;
52	char c;
53
54	if (_WRTCHK(iop)) {
55		iop->_flag |= _IOERR;
56#ifdef POSIX
57		errno = EBADF;
58#endif	/* POSIX */
59		return (EOF);
60	}
61	bufend = iop->_base + iop->_bufsiz;
62
63	if ((iop->_flag & _IONBF) == 0)  {
64		if (iop->_flag & _IOLBF) {
65			for ( ; ; ptr += n) {
66				while ((n = bufend - (cptr = iop->_ptr)) <= 0)
67					/* full buf */
68					if (_xflsbuf(iop) == EOF)
69						return(EOF);
70				if ((p = memnulccpy((char *) cptr, ptr, '\n', n)) != NULL) {
71					/*
72					 * Copy terminated either because we
73					 * saw a newline or we saw a NUL (end
74					 * of string).
75					 */
76					c = *(p - 1);	/* last character moved */
77					if (c == '\0')
78						p--;	/* didn't write '\0' */
79					n = p - (char *) cptr;
80				}
81				iop->_cnt -= n;
82				iop->_ptr += n;
83				_BUFSYNC(iop);
84				ndone += n;
85				if (p != NULL) {
86					/*
87					 * We found either a newline or a NUL.
88					 * If we found a newline, flush the
89					 * buffer.
90					 * If we found a NUL, we're done.
91					 */
92					if (c == '\n') {
93						if (_xflsbuf(iop) == EOF)
94							return(EOF);
95					} else {
96						/* done */
97						return(ndone);
98					}
99		       		}
100			}
101		} else {
102			for ( ; ; ptr += n) {
103				while ((n = bufend - (cptr = iop->_ptr)) <= 0)
104					/* full buf */
105					if (_xflsbuf(iop) == EOF)
106						return(EOF);
107				if ((p = memccpy((char *) cptr, ptr, '\0', n)) != NULL)
108					n = (p - (char *) cptr) - 1;
109				iop->_cnt -= n;
110				iop->_ptr += n;
111				_BUFSYNC(iop);
112				ndone += n;
113				if (p != NULL)  {
114					/* done */
115		       			return(ndone);
116		       		}
117			}
118		}
119	}  else  {
120		/* write out to an unbuffered file */
121		return (write(iop->_file, ptr, strlen(ptr)));
122	}
123}
124
125/*
126 * Copy s2 to s1, stopping if character c or a NUL is copied.
127 * Copy no more than n bytes.
128 * Return a pointer to the byte after character c or NUL in the copy,
129 * or NULL if c or NUL is not found in the first n bytes.
130 */
131static char *
132memnulccpy(char *s1, char *s2, int c, int n)
133{
134	int cmoved;
135
136	while (--n >= 0) {
137		cmoved = *s2++;
138		if ((*s1++ = cmoved) == '\0' || cmoved == c)
139			return (s1);
140	}
141	return (0);
142}
143