1/* Copyright (c) 2009  Dmitry Xmelkov
2   All rights reserved.
3
4   Redistribution and use in source and binary forms, with or without
5   modification, are permitted provided that the following conditions are met:
6
7   * Redistributions of source code must retain the above copyright
8     notice, this list of conditions and the following disclaimer.
9   * Redistributions in binary form must reproduce the above copyright
10     notice, this list of conditions and the following disclaimer in
11     the documentation and/or other materials provided with the
12     distribution.
13   * Neither the name of the copyright holders nor the names of
14     contributors may be used to endorse or promote products derived
15     from this software without specific prior written permission.
16
17  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  POSSIBILITY OF SUCH DAMAGE.
28*/
29
30/* $Id: strtok_rP.S 2503 2016-02-07 22:59:47Z joerg_wunsch $ */
31
32#if !defined(__AVR_TINY__)
33
34#if !defined(__DOXYGEN__)
35
36#include "asmdef.h"
37
38/*  char *strtok_r (char *s, const char *delim, char **last)
39    {
40	char *p = *last;
41	const char *q;
42	char c, d;
43
44	if (!s) {
45	    if (!p) return s;		// end of string
46	    s = p;			// continue parsing
47	}
48
49	p = s;
50	for (;;) {			// skip delimeters
51	    s = p;			// space optimization (vs. s = p-1)
52	    if (!(c = *p++)) {
53		s = 0;
54		p = 0;
55		goto ret;
56	    }
57	    q = delim;
58	    do {
59		if (!(d = *q++))
60		    goto find_end;
61	    } while (d != c);
62	}
63
64      find_end:
65	do {
66	    q = delim;
67	    do {
68		d = *q++;
69		if (c == d) {
70		    *--p = 0;
71		    p++;
72		    goto ret;
73		}
74	    } while (d);
75	} while ((c = *p++) != 0);
76	p = 0;				// stop parsing
77      ret:
78	*last = p;
79	return s;
80    }
81 */
82
83#define str_hi	r25
84#define str_lo	r24
85#define dlm_lo	r22
86#define lst_lo	r20
87
88ENTRY strtok_rP
89
90/* Two variants below are different in registers to load chars. In case
91   of enhanced core it is convinient to use <R0,R1> pair as zero word.
92   In classic case it is optimal to load delimeter char (flash) to R0.
93 */
94
95/* --------------------------------------------------------------------	*/
96#if	__AVR_HAVE_LPMX__
97
98# define dlm_ch r18		/* delimeter character	*/
99# define str_ch r0		/* string character	*/
100
101	X_movw	ZL, lst_lo
102	ld	XL, Z+			; X = *last
103	ld	XH, Z
104  ; check str
105	sbiw	str_lo, 0
106	brne	1f
107	sbiw	XL, 0
108	breq	.Lret			; end of string
109	X_movw	str_lo, XL		; continue parsing
110
111  ; skip delimeters
1121:	X_movw	XL, str_lo		; p = str
1132:	X_movw	str_lo, XL
114	ld	str_ch, X+
115	tst	str_ch
116	brne	3f
117	X_movw	str_lo, str_ch		; <r0,r1>
118	rjmp	.Lclr
1193:	X_movw	ZL, dlm_lo
1204:	lpm	dlm_ch, Z+
121	tst	dlm_ch
122	breq	5f			; goto find
123	cp	dlm_ch, str_ch
124	brne	4b
125	rjmp	2b			; skip 1 byte
126
127  ; find new token end
1285:	X_movw	ZL, dlm_lo
1296:	lpm	dlm_ch, Z+
130	cp	dlm_ch, str_ch		; str_ch != 0
131	brne	7f
132	st	-X, __zero_reg__
133	adiw	XL, 1
134	rjmp	.Lret
1357:	tst	dlm_ch
136	brne	6b
137  ; next str byte
138	ld	str_ch, X+
139	tst	str_ch
140	brne	5b
141
142  ; stop parsing
143.Lclr:	X_movw	XL, str_ch		; <r0,r1>
144  ; save last pointer
145.Lret:	X_movw	ZL, lst_lo		; *last = X
146	st	Z+, XL
147	st	Z, XH
148	ret
149
150/* --------------------------------------------------------------------	*/
151#else	/* !__AVR_HAVE_LPMX__ */
152
153# define dlm_ch r0		/* delimeter character	*/
154# define str_ch r18		/* string character	*/
155
156	X_movw	ZL, lst_lo
157	ld	XL, Z+			; X = *last
158	ld	XH, Z
159  ; check str
160	sbiw	str_lo, 0
161	brne	1f
162	sbiw	XL, 0
163	breq	.Lret			; end of string
164	X_movw	str_lo, XL		; continue parsing
165
166  ; skip delimeters
1671:	X_movw	XL, str_lo		; p = str
1682:	X_movw	str_lo, XL
169	ld	str_ch, X+
170	tst	str_ch
171	brne	3f
172	clr	str_lo			; return value
173	clr	str_hi
174	rjmp	.Lclr
1753:	X_movw	ZL, dlm_lo
1764:	lpm				; lpm r0,Z
177	adiw	ZL, 1
178	tst	dlm_ch
179	breq	5f			; goto find
180	cp	dlm_ch, str_ch
181	brne	4b
182	rjmp	2b			; skip 1 byte
183
184  ; find new token end
1855:	X_movw	ZL, dlm_lo
1866:	lpm				; lpm r0,Z
187	adiw	ZL, 1
188	cp	dlm_ch, str_ch		; str_ch != 0
189	brne	7f
190	st	-X, __zero_reg__
191	adiw	XL, 1
192	rjmp	.Lret
1937:	tst	dlm_ch
194	brne	6b
195  ; next str byte
196	ld	str_ch, X+
197	tst	str_ch
198	brne	5b
199
200  ; stop parsing
201.Lclr:	clr	XL
202	clr	XH
203  ; save last pointer
204.Lret:	X_movw	ZL, lst_lo		; *last = X
205	st	Z+, XL
206	st	Z, XH
207	ret
208
209/* --------------------------------------------------------------------	*/
210#endif	/* !__AVR_HAVE_LPMX__ */
211
212ENDFUNC
213
214#endif /* not __DOXYGEN__ */
215
216#endif /* !defined(__AVR_TINY__) */
217