xref: /csrg-svn/sys/kern/tty_subr.c (revision 49589)
1*49589Sbostic /*-
2*49589Sbostic  * Copyright (c) 1982, 1986 The Regents of the University of California.
3*49589Sbostic  * All rights reserved.
423391Smckusick  *
5*49589Sbostic  * %sccs.include.proprietary.c%
6*49589Sbostic  *
7*49589Sbostic  *	@(#)tty_subr.c	7.7 (Berkeley) 05/09/91
823391Smckusick  */
91892Swnj 
1017097Sbloom #include "param.h"
1117097Sbloom #include "systm.h"
1217097Sbloom #include "buf.h"
1317576Sbloom #include "ioctl.h"
1417097Sbloom #include "tty.h"
1517097Sbloom #include "clist.h"
1632Sbill 
171890Swnj char	cwaiting;
181890Swnj 
1935811Smarc #define setquote(cp) \
2035811Smarc 	setbit(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \
2135811Smarc 		(int)(cp)&CROUND)
2235811Smarc #define isquote(cp) \
2335811Smarc 	isset(((char *)((int)(cp)&~CROUND)+sizeof(struct cblock *)), \
2435811Smarc 		(int)(cp)&CROUND)
2535811Smarc #define cbptr(x) ((struct cblock *)(x))
2635811Smarc 
2732Sbill /*
2847545Skarels  * Initialize clist by freeing all character blocks.
2947545Skarels  */
3047545Skarels cinit()
3147545Skarels {
3247545Skarels 	register int ccp;
3347545Skarels 	register struct cblock *cp;
3447545Skarels 
3547545Skarels 	ccp = (int) cfree;
3647545Skarels 	ccp = (ccp + CROUND) & ~CROUND;
3747545Skarels 	for(cp = (struct cblock *) ccp; cp < &cfree[nclist - 1]; cp++) {
3847545Skarels 		cp->c_next = cfreelist;
3947545Skarels 		cfreelist = cp;
4047545Skarels 		cfreecount += CBSIZE;
4147545Skarels 	}
4247545Skarels }
4347545Skarels 
4447545Skarels /*
4532Sbill  * Character list get/put
4632Sbill  */
4732Sbill getc(p)
4812754Ssam 	register struct clist *p;
4932Sbill {
5032Sbill 	register struct cblock *bp;
5132Sbill 	register int c, s;
5232Sbill 
5317542Skarels 	s = spltty();
5432Sbill 	if (p->c_cc <= 0) {
5532Sbill 		c = -1;
5632Sbill 		p->c_cc = 0;
5732Sbill 		p->c_cf = p->c_cl = NULL;
5832Sbill 	} else {
5935811Smarc 		c = *p->c_cf & 0377;
6035811Smarc 		if (isquote(p->c_cf))
6135811Smarc 			c |= TTY_QUOTE;
6235811Smarc 		p->c_cf++;
6332Sbill 		if (--p->c_cc<=0) {
6435811Smarc 			bp = cbptr(p->c_cf-1);
6535811Smarc 			bp = cbptr((int)bp & ~CROUND);
6632Sbill 			p->c_cf = NULL;
6732Sbill 			p->c_cl = NULL;
6832Sbill 			bp->c_next = cfreelist;
6932Sbill 			cfreelist = bp;
701890Swnj 			cfreecount += CBSIZE;
711890Swnj 			if (cwaiting) {
721890Swnj 				wakeup(&cwaiting);
731890Swnj 				cwaiting = 0;
741890Swnj 			}
7532Sbill 		} else if (((int)p->c_cf & CROUND) == 0){
7635811Smarc 			bp = cbptr(p->c_cf);
7732Sbill 			bp--;
7832Sbill 			p->c_cf = bp->c_next->c_info;
7932Sbill 			bp->c_next = cfreelist;
8032Sbill 			cfreelist = bp;
811890Swnj 			cfreecount += CBSIZE;
821890Swnj 			if (cwaiting) {
831890Swnj 				wakeup(&cwaiting);
841890Swnj 				cwaiting = 0;
851890Swnj 			}
8632Sbill 		}
8732Sbill 	}
8832Sbill 	splx(s);
8926279Skarels 	return (c);
9032Sbill }
9132Sbill 
9232Sbill /*
9332Sbill  * copy clist to buffer.
9432Sbill  * return number of bytes moved.
9532Sbill  */
9632Sbill q_to_b(q, cp, cc)
979761Ssam 	register struct clist *q;
989761Ssam 	register char *cp;
9932Sbill {
10032Sbill 	register struct cblock *bp;
10132Sbill 	register int s;
10217542Skarels 	register nc;
10332Sbill 	char *acp;
10432Sbill 
10532Sbill 	if (cc <= 0)
10626279Skarels 		return (0);
10717542Skarels 	s = spltty();
10832Sbill 	if (q->c_cc <= 0) {
10932Sbill 		q->c_cc = 0;
11032Sbill 		q->c_cf = q->c_cl = NULL;
1111890Swnj 		splx(s);
11226279Skarels 		return (0);
11332Sbill 	}
11432Sbill 	acp = cp;
11532Sbill 
11617542Skarels 	while (cc) {
11726279Skarels 		nc = sizeof (struct cblock) - ((int)q->c_cf & CROUND);
11817542Skarels 		nc = MIN(nc, cc);
11917542Skarels 		nc = MIN(nc, q->c_cc);
12017542Skarels 		(void) bcopy(q->c_cf, cp, (unsigned)nc);
12117542Skarels 		q->c_cf += nc;
12217542Skarels 		q->c_cc -= nc;
12317542Skarels 		cc -= nc;
12417542Skarels 		cp += nc;
12517542Skarels 		if (q->c_cc <= 0) {
12635811Smarc 			bp = cbptr(q->c_cf - 1);
12735811Smarc 			bp = cbptr((int)bp & ~CROUND);
12832Sbill 			q->c_cf = q->c_cl = NULL;
12932Sbill 			bp->c_next = cfreelist;
13032Sbill 			cfreelist = bp;
1311890Swnj 			cfreecount += CBSIZE;
1321890Swnj 			if (cwaiting) {
1331890Swnj 				wakeup(&cwaiting);
1341890Swnj 				cwaiting = 0;
1351890Swnj 			}
13632Sbill 			break;
13732Sbill 		}
13832Sbill 		if (((int)q->c_cf & CROUND) == 0) {
13935811Smarc 			bp = cbptr(q->c_cf);
14032Sbill 			bp--;
14132Sbill 			q->c_cf = bp->c_next->c_info;
14232Sbill 			bp->c_next = cfreelist;
14332Sbill 			cfreelist = bp;
1441890Swnj 			cfreecount += CBSIZE;
1451890Swnj 			if (cwaiting) {
1461890Swnj 				wakeup(&cwaiting);
1471890Swnj 				cwaiting = 0;
1481890Swnj 			}
14932Sbill 		}
15032Sbill 	}
15132Sbill 	splx(s);
15226279Skarels 	return (cp-acp);
15332Sbill }
15432Sbill 
15532Sbill /*
15632Sbill  * Return count of contiguous characters
15732Sbill  * in clist starting at q->c_cf.
15832Sbill  * Stop counting if flag&character is non-null.
15932Sbill  */
16032Sbill ndqb(q, flag)
1619761Ssam 	register struct clist *q;
16232Sbill {
1639761Ssam 	register cc;
1649761Ssam 	int s;
16532Sbill 
16617542Skarels 	s = spltty();
16732Sbill 	if (q->c_cc <= 0) {
16832Sbill 		cc = -q->c_cc;
16932Sbill 		goto out;
17032Sbill 	}
17132Sbill 	cc = ((int)q->c_cf + CBSIZE) & ~CROUND;
17232Sbill 	cc -= (int)q->c_cf;
17332Sbill 	if (q->c_cc < cc)
17432Sbill 		cc = q->c_cc;
17532Sbill 	if (flag) {
17632Sbill 		register char *p, *end;
17732Sbill 
17832Sbill 		p = q->c_cf;
17932Sbill 		end = p;
18032Sbill 		end += cc;
18132Sbill 		while (p < end) {
18232Sbill 			if (*p & flag) {
1831890Swnj 				cc = (int)p;
1841890Swnj 				cc -= (int)q->c_cf;
18532Sbill 				break;
18632Sbill 			}
18732Sbill 			p++;
18832Sbill 		}
18932Sbill 	}
19032Sbill out:
19132Sbill 	splx(s);
19226279Skarels 	return (cc);
19332Sbill }
19432Sbill 
19532Sbill /*
1961890Swnj  * Flush cc bytes from q.
19732Sbill  */
19832Sbill ndflush(q, cc)
19912754Ssam 	register struct clist *q;
20012754Ssam 	register cc;
20132Sbill {
20212754Ssam 	register struct cblock *bp;
20312754Ssam 	char *end;
20412754Ssam 	int rem, s;
20532Sbill 
20617542Skarels 	s = spltty();
20726279Skarels 	if (q->c_cc <= 0)
20832Sbill 		goto out;
2091890Swnj 	while (cc>0 && q->c_cc) {
21035811Smarc 		bp = cbptr((int)q->c_cf & ~CROUND);
2111890Swnj 		if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
2121890Swnj 			end = q->c_cl;
2131890Swnj 		} else {
2141890Swnj 			end = (char *)((int)bp + sizeof (struct cblock));
2151890Swnj 		}
2161890Swnj 		rem = end - q->c_cf;
2171890Swnj 		if (cc >= rem) {
2181890Swnj 			cc -= rem;
2191890Swnj 			q->c_cc -= rem;
22032Sbill 			q->c_cf = bp->c_next->c_info;
2211890Swnj 			bp->c_next = cfreelist;
2221890Swnj 			cfreelist = bp;
2231890Swnj 			cfreecount += CBSIZE;
2241890Swnj 			if (cwaiting) {
2251890Swnj 				wakeup(&cwaiting);
2261890Swnj 				cwaiting = 0;
2271890Swnj 			}
22832Sbill 		} else {
2291890Swnj 			q->c_cc -= cc;
2301890Swnj 			q->c_cf += cc;
2311890Swnj 			if (q->c_cc <= 0) {
2321890Swnj 				bp->c_next = cfreelist;
2331890Swnj 				cfreelist = bp;
2341890Swnj 				cfreecount += CBSIZE;
2351890Swnj 				if (cwaiting) {
2361890Swnj 					wakeup(&cwaiting);
2371890Swnj 					cwaiting = 0;
2381890Swnj 				}
2391890Swnj 			}
2401890Swnj 			break;
24132Sbill 		}
2421890Swnj 	}
2431890Swnj 	if (q->c_cc <= 0) {
24432Sbill 		q->c_cf = q->c_cl = NULL;
2451890Swnj 		q->c_cc = 0;
24632Sbill 	}
24732Sbill out:
24832Sbill 	splx(s);
24932Sbill }
250172Sbill 
2511890Swnj 
25232Sbill putc(c, p)
25312754Ssam 	register struct clist *p;
25432Sbill {
25532Sbill 	register struct cblock *bp;
25632Sbill 	register char *cp;
25732Sbill 	register s;
25832Sbill 
25917542Skarels 	s = spltty();
26035811Smarc 	if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {	/* no cblocks yet */
26132Sbill 		if ((bp = cfreelist) == NULL) {
26232Sbill 			splx(s);
26326279Skarels 			return (-1);
26432Sbill 		}
26532Sbill 		cfreelist = bp->c_next;
2661890Swnj 		cfreecount -= CBSIZE;
26732Sbill 		bp->c_next = NULL;
26835811Smarc 		bzero(bp->c_quote, CBQSIZE);
26932Sbill 		p->c_cf = cp = bp->c_info;
27032Sbill 	} else if (((int)cp & CROUND) == 0) {
27135811Smarc 		bp = cbptr(cp) - 1;	/* pointer arith */
27232Sbill 		if ((bp->c_next = cfreelist) == NULL) {
27332Sbill 			splx(s);
27426279Skarels 			return (-1);
27532Sbill 		}
27632Sbill 		bp = bp->c_next;
27732Sbill 		cfreelist = bp->c_next;
2781890Swnj 		cfreecount -= CBSIZE;
27932Sbill 		bp->c_next = NULL;
28032Sbill 		cp = bp->c_info;
28132Sbill 	}
28235811Smarc 	if (c&TTY_QUOTE)
28335811Smarc 		setquote(cp);
28432Sbill 	*cp++ = c;
28532Sbill 	p->c_cc++;
28632Sbill 	p->c_cl = cp;
28732Sbill 	splx(s);
28826279Skarels 	return (0);
28932Sbill }
29032Sbill 
29132Sbill /*
29232Sbill  * copy buffer to clist.
29332Sbill  * return number of bytes not transfered.
29432Sbill  */
29532Sbill b_to_q(cp, cc, q)
29612754Ssam 	register char *cp;
29712754Ssam 	struct clist *q;
29812754Ssam 	register int cc;
29932Sbill {
30032Sbill 	register char *cq;
30132Sbill 	register struct cblock *bp;
30217542Skarels 	register s, nc;
30317542Skarels 	int acc;
30432Sbill 
30532Sbill 	if (cc <= 0)
30626279Skarels 		return (0);
30717542Skarels 	acc = cc;
30817542Skarels 	s = spltty();
30917542Skarels 	if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
31017542Skarels 		if ((bp = cfreelist) == NULL)
31117542Skarels 			goto out;
31217542Skarels 		cfreelist = bp->c_next;
31317542Skarels 		cfreecount -= CBSIZE;
31435811Smarc 		bzero(bp->c_quote, CBQSIZE);
31517542Skarels 		bp->c_next = NULL;
31617542Skarels 		q->c_cf = cq = bp->c_info;
31717542Skarels 	}
31817542Skarels 
31917542Skarels 	while (cc) {
32032Sbill 		if (((int)cq & CROUND) == 0) {
32135811Smarc 			bp = cbptr(cq) - 1;
32217542Skarels 			if ((bp->c_next = cfreelist) == NULL)
32317542Skarels 				goto out;
32432Sbill 			bp = bp->c_next;
32532Sbill 			cfreelist = bp->c_next;
3261890Swnj 			cfreecount -= CBSIZE;
32735811Smarc 			bzero(bp->c_quote, CBQSIZE);
32832Sbill 			bp->c_next = NULL;
32917542Skarels 			cq = bp->c_info;
33032Sbill 		}
33126279Skarels 		nc = MIN(cc, sizeof (struct cblock) - ((int)cq & CROUND));
33217542Skarels 		(void) bcopy(cp, cq, (unsigned)nc);
33317542Skarels 		cp += nc;
33417542Skarels 		cq += nc;
33517542Skarels 		cc -= nc;
33632Sbill 	}
33717542Skarels out:
33817542Skarels 	q->c_cl = cq;
33917542Skarels 	q->c_cc += acc - cc;
34017542Skarels 	splx(s);
34117368Ssam 	return (cc);
34232Sbill }
34332Sbill 
34432Sbill /*
345172Sbill  * Given a non-NULL pointter into the list (like c_cf which
346172Sbill  * always points to a real character if non-NULL) return the pointer
347172Sbill  * to the next character in the list or return NULL if no more chars.
348172Sbill  *
349172Sbill  * Callers must not allow getc's to happen between nextc's so that the
350172Sbill  * pointer becomes invalid.  Note that interrupts are NOT masked.
351172Sbill  */
352172Sbill char *
35335811Smarc nextc(p, cp, c)
35412754Ssam 	register struct clist *p;
35512754Ssam 	register char *cp;
35635811Smarc 	register int *c;
357172Sbill {
358172Sbill 
359172Sbill 	if (p->c_cc && ++cp != p->c_cl) {
36035811Smarc 		if (((int)cp & CROUND) == 0) {
36135811Smarc 			cp = (cbptr(cp))[-1].c_next->c_info;
36235811Smarc 		}
36335811Smarc 		*c = *cp;
36435811Smarc 		if (isquote(cp))
36535811Smarc 			*c |= TTY_QUOTE;
366172Sbill 		return (cp);
367172Sbill 	}
368172Sbill 	return (0);
369172Sbill }
370172Sbill 
371172Sbill /*
372172Sbill  * Remove the last character in the list and return it.
373172Sbill  */
374172Sbill unputc(p)
37512754Ssam 	register struct clist *p;
376172Sbill {
377172Sbill 	register struct cblock *bp;
378172Sbill 	register int c, s;
379172Sbill 	struct cblock *obp;
380172Sbill 
38117542Skarels 	s = spltty();
382172Sbill 	if (p->c_cc <= 0)
383172Sbill 		c = -1;
384172Sbill 	else {
385172Sbill 		c = *--p->c_cl;
38635811Smarc 		if (isquote(p->c_cl))
38735811Smarc 			c |= TTY_QUOTE;
388172Sbill 		if (--p->c_cc <= 0) {
38935811Smarc 			bp = cbptr(p->c_cl);
39035811Smarc 			bp = cbptr((int)bp & ~CROUND);
391172Sbill 			p->c_cl = p->c_cf = NULL;
392172Sbill 			bp->c_next = cfreelist;
393172Sbill 			cfreelist = bp;
3941890Swnj 			cfreecount += CBSIZE;
39535811Smarc 		} else if (p->c_cl == (cbptr((int)p->c_cl & ~CROUND))->c_info) {
396172Sbill 			p->c_cl = (char *)((int)p->c_cl & ~CROUND);
39735811Smarc 
39835811Smarc 			bp = cbptr(p->c_cf);
39935811Smarc 			bp = cbptr((int)bp & ~CROUND);
40035811Smarc 			while (bp->c_next != cbptr(p->c_cl))
401172Sbill 				bp = bp->c_next;
402172Sbill 			obp = bp;
403172Sbill 			p->c_cl = (char *)(bp + 1);
404172Sbill 			bp = bp->c_next;
405172Sbill 			bp->c_next = cfreelist;
406172Sbill 			cfreelist = bp;
4071890Swnj 			cfreecount += CBSIZE;
408172Sbill 			obp->c_next = NULL;
409172Sbill 		}
410172Sbill 	}
411172Sbill 	splx(s);
412172Sbill 	return (c);
413172Sbill }
414172Sbill 
415172Sbill /*
416172Sbill  * Put the chars in the from que
417172Sbill  * on the end of the to que.
418172Sbill  */
419172Sbill catq(from, to)
42012754Ssam 	struct clist *from, *to;
421172Sbill {
42235811Smarc #ifdef notdef
42317542Skarels 	char bbuf[CBSIZE*4];
42435811Smarc #endif
42517542Skarels 	register s, c;
426172Sbill 
42717542Skarels 	s = spltty();
42817542Skarels 	if (to->c_cc == 0) {
42917542Skarels 		*to = *from;
43017542Skarels 		from->c_cc = 0;
43117542Skarels 		from->c_cf = NULL;
43217542Skarels 		from->c_cl = NULL;
43317542Skarels 		splx(s);
43417542Skarels 		return;
43517542Skarels 	}
43617542Skarels 	splx(s);
43735811Smarc #ifdef notdef
43817542Skarels 	while (from->c_cc > 0) {
43917542Skarels 		c = q_to_b(from, bbuf, sizeof bbuf);
44017542Skarels 		(void) b_to_q(bbuf, c, to);
44117542Skarels 	}
44235811Smarc #endif
44335811Smarc 	/* XXX - FIX */
44435811Smarc 	while ((c = getc(from)) >= 0)
44535811Smarc 		putc(c, to);
446172Sbill }
447172Sbill 
44817542Skarels #ifdef unneeded
449172Sbill /*
45026279Skarels  * Integer (short) get/put using clists.
45132Sbill  */
45217542Skarels typedef	u_short word_t;
4539761Ssam 
45432Sbill getw(p)
4558955Sroot 	register struct clist *p;
45632Sbill {
45717542Skarels 	register int s, c;
45817542Skarels 	register struct cblock *bp;
45932Sbill 
46017542Skarels 	if (p->c_cc <= 1)
46117542Skarels 		return(-1);
46217542Skarels 	if (p->c_cc & 01) {
46317542Skarels 		c = getc(p);
46433398Smckusick #if BYTE_ORDER == LITTLE_ENDIAN
46526279Skarels 		return (c | (getc(p)<<8));
46626279Skarels #else
46726279Skarels 		return (getc(p) | (c<<8));
46826279Skarels #endif
46917542Skarels 	}
47017542Skarels 	s = spltty();
47135811Smarc #if BYTE_ORDER == LITTLE_ENDIAN
47229947Skarels 	c = (((u_char *)p->c_cf)[0] << 8) | ((u_char *)p->c_cf)[1];
47326279Skarels #else
47426279Skarels 	c = (((u_char *)p->c_cf)[1] << 8) | ((u_char *)p->c_cf)[0];
47526279Skarels #endif
47626279Skarels 	p->c_cf += sizeof (word_t);
47726279Skarels 	p->c_cc -= sizeof (word_t);
47817542Skarels 	if (p->c_cc <= 0) {
47935811Smarc 		bp = cbptr(p->c_cf-1);
48035811Smarc 		bp = cbptr((int)bp & ~CROUND);
48117542Skarels 		p->c_cf = NULL;
48217542Skarels 		p->c_cl = NULL;
48317542Skarels 		bp->c_next = cfreelist;
48417542Skarels 		cfreelist = bp;
48517542Skarels 		cfreecount += CBSIZE;
48617542Skarels 		if (cwaiting) {
48717542Skarels 			wakeup(&cwaiting);
48817542Skarels 			cwaiting = 0;
48917542Skarels 		}
49017542Skarels 	} else if (((int)p->c_cf & CROUND) == 0) {
49135811Smarc 		bp = cbptr(p->c_cf);
49217542Skarels 		bp--;
49317542Skarels 		p->c_cf = bp->c_next->c_info;
49417542Skarels 		bp->c_next = cfreelist;
49517542Skarels 		cfreelist = bp;
49617542Skarels 		cfreecount += CBSIZE;
49717542Skarels 		if (cwaiting) {
49817542Skarels 			wakeup(&cwaiting);
49917542Skarels 			cwaiting = 0;
50017542Skarels 		}
50117542Skarels 	}
50217542Skarels 	splx(s);
50317542Skarels 	return (c);
50432Sbill }
50532Sbill 
50632Sbill putw(c, p)
5078955Sroot 	register struct clist *p;
50817542Skarels 	word_t c;
50932Sbill {
51032Sbill 	register s;
51117542Skarels 	register struct cblock *bp;
51217542Skarels 	register char *cp;
51332Sbill 
51417542Skarels 	s = spltty();
51532Sbill 	if (cfreelist==NULL) {
51632Sbill 		splx(s);
51732Sbill 		return(-1);
51832Sbill 	}
51917542Skarels 	if (p->c_cc & 01) {
52033398Smckusick #if BYTE_ORDER == LITTLE_ENDIAN
52117542Skarels 		(void) putc(c, p);
52217542Skarels 		(void) putc(c>>8, p);
52326279Skarels #else
52426279Skarels 		(void) putc(c>>8, p);
52526279Skarels 		(void) putc(c, p);
52626279Skarels #endif
52717542Skarels 	} else {
52817542Skarels 		if ((cp = p->c_cl) == NULL || p->c_cc < 0 ) {
52917542Skarels 			if ((bp = cfreelist) == NULL) {
53017542Skarels 				splx(s);
53117542Skarels 				return (-1);
53217542Skarels 			}
53317542Skarels 			cfreelist = bp->c_next;
53417542Skarels 			cfreecount -= CBSIZE;
53517542Skarels 			bp->c_next = NULL;
53617542Skarels 			p->c_cf = cp = bp->c_info;
53717542Skarels 		} else if (((int)cp & CROUND) == 0) {
53835811Smarc 			bp = cbptr(cp) - 1;
53917542Skarels 			if ((bp->c_next = cfreelist) == NULL) {
54017542Skarels 				splx(s);
54117542Skarels 				return (-1);
54217542Skarels 			}
54317542Skarels 			bp = bp->c_next;
54417542Skarels 			cfreelist = bp->c_next;
54517542Skarels 			cfreecount -= CBSIZE;
54617542Skarels 			bp->c_next = NULL;
54717542Skarels 			cp = bp->c_info;
54817542Skarels 		}
54926279Skarels #if defined(vax)
55017542Skarels 		*(word_t *)cp = c;
55126279Skarels #else
55226279Skarels 		((u_char *)cp)[0] = c>>8;
55326279Skarels 		((u_char *)cp)[1] = c;
55426279Skarels #endif
55526279Skarels 		p->c_cl = cp + sizeof (word_t);
55626279Skarels 		p->c_cc += sizeof (word_t);
55717542Skarels 	}
55832Sbill 	splx(s);
5599761Ssam 	return (0);
56032Sbill }
56117542Skarels #endif unneeded
562