1 /* $NetBSD: parse.c,v 1.13 2009/01/18 00:24:29 lukem Exp $ */
4 * Copyright (c) 2008 David Young. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: parse.c,v 1.13 2009/01/18 00:24:29 lukem Exp $");
42 #include <arpa/inet.h>
43 #include <sys/param.h>
45 #include <net/if_dl.h>
46 #include <netatalk/at.h>
47 #include <netiso/iso.h>
53 #define dbg_warnx(__fmt, ...) /* empty */
55 static int parser_default_init(struct parser
*);
56 static int pbranch_init(struct parser
*);
57 static int pkw_init(struct parser
*);
59 static int pterm_match(const struct parser
*, const struct match
*,
60 struct match
*, int, const char *);
62 static int paddr_match(const struct parser
*, const struct match
*,
63 struct match
*, int, const char *);
65 static int pbranch_match(const struct parser
*, const struct match
*,
66 struct match
*, int, const char *);
68 static int piface_match(const struct parser
*, const struct match
*,
69 struct match
*, int, const char *);
71 static int pstr_match(const struct parser
*, const struct match
*,
72 struct match
*, int, const char *);
74 static int pinteger_match(const struct parser
*, const struct match
*,
75 struct match
*, int, const char *);
77 static int pkw_match(const struct parser
*, const struct match
*,
78 struct match
*, int, const char *);
80 const struct parser_methods pterm_methods
= {
81 .pm_match
= pterm_match
85 const struct parser_methods pstr_methods
= {
86 .pm_match
= pstr_match
87 , .pm_init
= parser_default_init
90 const struct parser_methods pinteger_methods
= {
91 .pm_match
= pinteger_match
92 , .pm_init
= parser_default_init
95 const struct parser_methods paddr_methods
= {
96 .pm_match
= paddr_match
97 , .pm_init
= parser_default_init
100 const struct parser_methods piface_methods
= {
101 .pm_match
= piface_match
102 , .pm_init
= parser_default_init
105 const struct parser_methods pbranch_methods
= {
106 .pm_match
= pbranch_match
107 , .pm_init
= pbranch_init
110 const struct parser_methods pkw_methods
= {
111 .pm_match
= pkw_match
112 , .pm_init
= pkw_init
116 match_setenv(const struct match
*im
, struct match
*om
, const char *key
,
120 om
->m_env
= prop_dictionary_create();
122 om
->m_env
= prop_dictionary_copy(im
->m_env
);
124 if (om
->m_env
== NULL
)
127 if (key
!= NULL
&& !prop_dictionary_set(om
->m_env
, key
, o
))
131 prop_object_release((prop_object_t
)o
);
135 prop_object_release((prop_object_t
)om
->m_env
);
138 prop_object_release((prop_object_t
)o
);
144 pstr_match(const struct parser
*p
, const struct match
*im
, struct match
*om
,
145 int argidx
, const char *arg
)
148 const struct pstr
*ps
= (const struct pstr
*)p
;
157 len
= (int)sizeof(buf
);
158 if (get_string(arg
, NULL
, buf
, &len
) == NULL
) {
163 o
= (prop_object_t
)prop_data_create_data(buf
, len
);
170 if (match_setenv(im
, om
, ps
->ps_key
, o
) == -1)
173 om
->m_argidx
= argidx
;
175 om
->m_nextparser
= p
->p_nextparser
;
181 pinteger_match(const struct parser
*p
, const struct match
*im
, struct match
*om
,
182 int argidx
, const char *arg
)
185 const struct pinteger
*pi
= (const struct pinteger
*)p
;
194 val
= strtoimax(arg
, &end
, pi
->pi_base
);
195 if ((val
== INTMAX_MIN
|| val
== INTMAX_MAX
) && errno
== ERANGE
)
203 if (val
< pi
->pi_min
|| val
> pi
->pi_max
) {
208 o
= (prop_object_t
)prop_number_create_integer(val
);
215 if (match_setenv(im
, om
, pi
->pi_key
, o
) == -1)
218 om
->m_argidx
= argidx
;
220 om
->m_nextparser
= p
->p_nextparser
;
226 parse_linkaddr(const char *addr
, struct sockaddr_storage
*ss
)
228 static const size_t maxlen
=
229 sizeof(*ss
) - offsetof(struct sockaddr_dl
, sdl_data
[0]);
231 LLADDR_S_INITIAL
= 0,
232 LLADDR_S_ONE_OCTET
= 1,
233 LLADDR_S_TWO_OCTETS
= 2,
235 } state
= LLADDR_S_INITIAL
;
236 uint8_t octet
= 0, val
;
237 struct sockaddr_dl
*sdl
;
241 memset(ss
, 0, sizeof(*ss
));
242 ss
->ss_family
= AF_LINK
;
243 sdl
= (struct sockaddr_dl
*)ss
;
245 for (i
= 0, p
= addr
; i
< maxlen
; p
++) {
246 dbg_warnx("%s.%d: *p == %c, state %d", __func__
, __LINE__
, *p
,
249 dbg_warnx("%s.%d", __func__
, __LINE__
);
250 if (state
!= LLADDR_S_ONE_OCTET
&&
251 state
!= LLADDR_S_TWO_OCTETS
)
253 dbg_warnx("%s.%d", __func__
, __LINE__
);
254 sdl
->sdl_data
[i
++] = octet
;
256 offsetof(struct sockaddr_dl
, sdl_data
[i
]);
261 dbg_warnx("%s.%d", __func__
, __LINE__
);
262 if (state
!= LLADDR_S_ONE_OCTET
&&
263 state
!= LLADDR_S_TWO_OCTETS
)
265 dbg_warnx("%s.%d", __func__
, __LINE__
);
266 sdl
->sdl_data
[i
++] = octet
;
267 state
= LLADDR_S_COLON
;
270 if ('a' <= *p
&& *p
<= 'f')
272 else if ('A' <= *p
&& *p
<= 'F')
274 else if ('0' <= *p
&& *p
<= '9')
279 dbg_warnx("%s.%d", __func__
, __LINE__
);
280 if (state
== LLADDR_S_ONE_OCTET
) {
281 state
= LLADDR_S_TWO_OCTETS
;
284 } else if (state
!= LLADDR_S_INITIAL
&& state
!= LLADDR_S_COLON
)
287 state
= LLADDR_S_ONE_OCTET
;
290 dbg_warnx("%s.%d", __func__
, __LINE__
);
296 paddr_match(const struct parser
*p
, const struct match
*im
, struct match
*om
,
297 int argidx
, const char *arg0
)
299 unsigned int net
, node
;
303 struct sockaddr_at sat
;
304 struct sockaddr_iso siso
;
305 struct sockaddr_in sin
;
306 struct sockaddr_storage ss
;
308 const struct paddr
*pa
= (const struct paddr
*)p
;
313 struct paddr_prefix
*pfx
, *mask
;
314 const struct sockaddr
*sa
= NULL
;
315 struct addrinfo hints
, *result
= NULL
;
316 char *arg
, *end
, *plen
= NULL
, *servname0
;
317 const char *servname
;
326 if (pa
->pa_activator
!= NULL
&&
327 prop_dictionary_get(im
->m_env
, pa
->pa_activator
) == NULL
)
330 if (pa
->pa_deactivator
!= NULL
&&
331 prop_dictionary_get(im
->m_env
, pa
->pa_deactivator
) != NULL
)
334 if (!prop_dictionary_get_int64(im
->m_env
, "af", &af0
))
339 memset(&u
, 0, sizeof(u
));
345 if ((arg
= strdup(arg0
)) == NULL
)
349 (void)strsep(&servname0
, ",");
350 servname
= (servname0
== NULL
) ? "0" : servname0
;
352 if (pa
->pa_maskkey
== NULL
)
354 else if ((plen
= strrchr(arg
, '/')) != NULL
)
357 memset(&hints
, 0, sizeof(hints
));
359 hints
.ai_flags
= AI_NUMERICHOST
| AI_PASSIVE
;
360 hints
.ai_family
= af
;
361 hints
.ai_socktype
= SOCK_DGRAM
;
364 rc
= getaddrinfo(arg
, servname
, &hints
, &result
);
366 if (result
->ai_next
== NULL
)
367 sa
= result
->ai_addr
;
371 } else if ((hints
.ai_flags
& AI_NUMERICHOST
) != 0 &&
372 (af
== AF_INET
|| af
== AF_UNSPEC
) &&
373 inet_aton(arg
, &u
.sin
.sin_addr
) == 1) {
374 u
.sin
.sin_family
= AF_INET
;
375 u
.sin
.sin_len
= sizeof(u
.sin
);
378 } else if ((hints
.ai_flags
& AI_NUMERICHOST
) == 0 ||
383 hints
.ai_flags
&= ~AI_NUMERICHOST
;
390 prefixlen
= strtol(plen
, &end
, 10);
391 if (end
!= NULL
&& *end
!= '\0')
393 if (prefixlen
< 0 || prefixlen
>= UINT8_MAX
) {
400 if (sa
!= NULL
|| af
!= AF_UNSPEC
)
404 if (sscanf(arg0
, "%u.%u%n", &net
, &node
, &nread
) == 2 &&
405 net
!= 0 && net
<= 0xffff && node
!= 0 && node
<= 0xfe &&
406 arg0
[nread
] == '\0') {
407 u
.sat
.sat_family
= AF_APPLETALK
;
408 u
.sat
.sat_len
= sizeof(u
.sat
);
409 u
.sat
.sat_addr
.s_net
= htons(net
);
410 u
.sat
.sat_addr
.s_node
= node
;
415 u
.siso
.siso_len
= sizeof(u
.siso
);
416 u
.siso
.siso_family
= AF_ISO
;
417 /* XXX iso_addr(3) matches ANYTHING! */
418 u
.siso
.siso_addr
= *iso_addr(arg0
);
422 if (parse_linkaddr(arg0
, &u
.ss
) == -1)
432 len
= offsetof(struct paddr_prefix
, pfx_addr
) + sa
->sa_len
;
434 if ((pfx
= malloc(len
)) == NULL
)
441 for (i
= 0; i
< sa
->sa_len
; i
++)
442 printf(" %02x", ((const uint8_t *)sa
)[i
]);
447 pfx
->pfx_len
= (int16_t)prefixlen
;
448 memcpy(&pfx
->pfx_addr
, sa
, sa
->sa_len
);
452 freeaddrinfo(result
);
454 o
= (prop_object_t
)prop_data_create_data(pfx
, len
);
461 if (match_setenv(im
, om
, pa
->pa_addrkey
, o
) == -1)
464 if (pa
->pa_maskkey
!= NULL
&& plen
!= NULL
) {
467 if ((mask
= prefixlen_to_mask(af
, prefixlen
)) == NULL
) {
468 err(EXIT_FAILURE
, "%s: prefixlen_to_mask(%d, %ld)",
469 __func__
, af
, prefixlen
);
473 masklen
= paddr_prefix_size(mask
);
475 d
= prop_data_create_data(mask
, masklen
);
479 err(EXIT_FAILURE
, "%s: prop_data_create_data",
484 rc
= prop_dictionary_set(om
->m_env
, pa
->pa_maskkey
,
485 (prop_object_t
)d
) ? 0 : -1;
487 prop_object_release((prop_object_t
)d
);
490 err(EXIT_FAILURE
, "%s: prop_dictionary_set", __func__
);
495 om
->m_argidx
= argidx
;
497 om
->m_nextparser
= p
->p_nextparser
;
502 pterm_match(const struct parser
*p
, const struct match
*im
,
503 struct match
*om
, int argidx
, const char *arg
)
505 const struct pterm
*pt
= (const struct pterm
*)p
;
512 b
= prop_bool_create(true);
514 if (match_setenv(im
, om
, pt
->pt_key
, (prop_object_t
)b
) == -1)
517 om
->m_argidx
= argidx
;
519 om
->m_nextparser
= NULL
;
524 piface_match(const struct parser
*p
, const struct match
*im
,
525 struct match
*om
, int argidx
, const char *arg
)
527 const struct piface
*pif
= (const struct piface
*)p
;
530 if (arg
== NULL
|| strlen(arg
) > IFNAMSIZ
) {
535 if ((o
= (prop_object_t
)prop_string_create_cstring(arg
)) == NULL
) {
540 if (match_setenv(im
, om
, pif
->pif_key
, o
) == -1)
543 om
->m_argidx
= argidx
;
545 om
->m_nextparser
= p
->p_nextparser
;
550 match_cleanup(struct match
*dst
)
552 if (dst
->m_env
!= NULL
)
553 prop_object_release((prop_object_t
)dst
->m_env
);
554 memset(dst
, 0, sizeof(*dst
));
558 match_copy(struct match
*dst
, const struct match
*src
)
562 prop_object_retain((prop_object_t
)src
->m_env
);
567 pbranch_match(const struct parser
*p
, const struct match
*im
,
568 struct match
*om
, int argidx
, const char *arg
)
570 const struct parser
*nextp
;
572 const struct pbranch
*pb
= (const struct pbranch
*)p
;
574 int nforbid
= 0, nmatch
= 0, rc
;
575 parser_match_t matchfunc
;
577 memset(&tmpm
, 0, sizeof(tmpm
));
579 SIMPLEQ_FOREACH(b
, &pb
->pb_branches
, b_next
) {
580 dbg_warnx("%s: b->b_nextparser %p", __func__
,
581 (const void *)b
->b_nextparser
);
582 nextp
= b
->b_nextparser
;
586 match_setenv(im
, om
, NULL
, NULL
);
587 om
->m_nextparser
= NULL
;
589 om
->m_argidx
= argidx
;
593 matchfunc
= nextp
->p_methods
->pm_match
;
594 rc
= (*matchfunc
)(nextp
, im
, &tmpm
, argidx
, arg
);
596 match_copy(om
, &tmpm
);
597 match_cleanup(&tmpm
);
599 dbg_warnx("%s: branch %s ok", __func__
, nextp
->p_name
);
600 if (pb
->pb_match_first
)
602 } else if (rc
== 1) {
604 if (pb
->pb_match_first
)
607 dbg_warnx("%s: fail branch %s", __func__
,
614 return (nforbid
== 0) ? -1 : 1;
616 dbg_warnx("%s: branch ok", __func__
);
626 pkw_match(const struct parser
*p
, const struct match
*im
,
627 struct match
*om
, int argidx
, const char *arg
)
629 prop_object_t o
= NULL
;
631 union kwval
*u
= NULL
;
632 const struct pkw
*pk
= (const struct pkw
*)p
;
639 SIMPLEQ_FOREACH(k
, &pk
->pk_keywords
, k_next
) {
640 if (k
->k_act
!= NULL
&&
641 prop_dictionary_get(im
->m_env
, k
->k_act
) == NULL
)
644 if (k
->k_neg
&& arg
[0] == '-' &&
645 strcmp(k
->k_word
, arg
+ 1) == 0)
647 else if (strcmp(k
->k_word
, arg
) == 0)
652 if (k
->k_altdeact
!= NULL
&&
653 prop_dictionary_get(im
->m_env
, k
->k_altdeact
) != NULL
)
656 if (k
->k_deact
!= NULL
&&
657 prop_dictionary_get(im
->m_env
, k
->k_deact
) != NULL
)
669 o
= (prop_object_t
)prop_bool_create(u
->u_bool
);
674 o
= (prop_object_t
)prop_number_create_integer(u
->u_sint
);
679 o
= (prop_object_t
)prop_number_create_unsigned_integer(
688 o
= (prop_object_t
)prop_string_create_cstring_nocopy(u
->u_str
);
693 errx(EXIT_FAILURE
, "unknown keyword type %d", k
->k_type
);
696 if (match_setenv(im
, om
, (o
== NULL
) ? NULL
: k
->k_key
, o
) == -1)
699 om
->m_argidx
= argidx
;
701 om
->m_nextparser
= k
->k_nextparser
;
702 om
->m_exec
= k
->k_exec
;
710 paddr_create(const char *name
, parser_exec_t pexec
, const char *addrkey
,
711 const char *maskkey
, struct parser
*next
)
715 if ((pa
= calloc(sizeof(*pa
), 1)) == NULL
)
718 pa
->pa_parser
.p_methods
= &paddr_methods
;
719 pa
->pa_parser
.p_exec
= pexec
;
720 pa
->pa_parser
.p_name
= name
;
721 pa
->pa_parser
.p_nextparser
= next
;
723 pa
->pa_addrkey
= addrkey
;
724 pa
->pa_maskkey
= maskkey
;
730 piface_create(const char *name
, parser_exec_t pexec
, const char *defkey
,
731 struct parser
*defnext
)
735 if ((pif
= calloc(sizeof(*pif
), 1)) == NULL
)
738 pif
->pif_parser
.p_methods
= &piface_methods
;
739 pif
->pif_parser
.p_exec
= pexec
;
740 pif
->pif_parser
.p_name
= name
;
741 pif
->pif_parser
.p_nextparser
= defnext
;
743 pif
->pif_key
= defkey
;
749 pbranch_addbranch(struct pbranch
*pb
, struct parser
*p
)
753 if ((b
= malloc(sizeof(*b
))) == NULL
)
756 SIMPLEQ_INSERT_HEAD(&pb
->pb_branches
, b
, b_next
);
757 pb
->pb_parser
.p_initialized
= false;
758 return parser_init(&pb
->pb_parser
);
762 pbranch_setbranches(struct pbranch
*pb
, const struct branch
*brs
, size_t nbr
)
767 dbg_warnx("%s: nbr %zu", __func__
, nbr
);
769 while ((b
= SIMPLEQ_FIRST(&pb
->pb_branches
)) != NULL
) {
770 SIMPLEQ_REMOVE_HEAD(&pb
->pb_branches
, b_next
);
774 for (i
= 0; i
< nbr
; i
++) {
775 if ((b
= malloc(sizeof(*b
))) == NULL
)
778 dbg_warnx("%s: b->b_nextparser %p", __func__
,
779 (const void *)b
->b_nextparser
);
780 SIMPLEQ_INSERT_TAIL(&pb
->pb_branches
, b
, b_next
);
785 while ((b
= SIMPLEQ_FIRST(&pb
->pb_branches
)) != NULL
) {
786 SIMPLEQ_REMOVE_HEAD(&pb
->pb_branches
, b_next
);
793 pbranch_init(struct parser
*p
)
796 struct pbranch
*pb
= (struct pbranch
*)p
;
799 if (pb
->pb_nbrinit
== 0)
801 else if (pbranch_setbranches(pb
, pb
->pb_brinit
, pb
->pb_nbrinit
) == -1)
806 SIMPLEQ_FOREACH(b
, &pb
->pb_branches
, b_next
) {
807 np
= b
->b_nextparser
;
808 if (np
!= NULL
&& parser_init(np
) == -1)
815 pbranch_create(const char *name
, const struct branch
*brs
, size_t nbr
,
820 dbg_warnx("%s: nbr %zu", __func__
, nbr
);
822 if ((pb
= calloc(1, sizeof(*pb
))) == NULL
)
825 pb
->pb_parser
.p_methods
= &pbranch_methods
;
826 pb
->pb_parser
.p_name
= name
;
828 SIMPLEQ_INIT(&pb
->pb_branches
);
830 if (pbranch_setbranches(pb
, brs
, nbr
) == -1)
833 pb
->pb_match_first
= match_first
;
841 parser_default_init(struct parser
*p
)
845 np
= p
->p_nextparser
;
846 if (np
!= NULL
&& parser_init(np
) == -1)
853 pkw_setwords(struct pkw
*pk
, parser_exec_t defexec
, const char *defkey
,
854 const struct kwinst
*kws
, size_t nkw
, struct parser
*defnext
)
859 for (i
= 0; i
< nkw
; i
++) {
860 if (kws
[i
].k_word
== NULL
)
862 if ((k
= malloc(sizeof(*k
))) == NULL
)
865 if (k
->k_nextparser
== NULL
)
866 k
->k_nextparser
= defnext
;
867 if (k
->k_key
== NULL
)
869 if (k
->k_exec
== NULL
)
871 SIMPLEQ_INSERT_TAIL(&pk
->pk_keywords
, k
, k_next
);
876 while ((k
= SIMPLEQ_FIRST(&pk
->pk_keywords
)) != NULL
) {
877 SIMPLEQ_REMOVE_HEAD(&pk
->pk_keywords
, k_next
);
884 pkw_init(struct parser
*p
)
887 struct pkw
*pk
= (struct pkw
*)p
;
890 if (pk
->pk_nkwinit
== 0)
892 else if (pkw_setwords(pk
, pk
->pk_execinit
, pk
->pk_keyinit
,
893 pk
->pk_kwinit
, pk
->pk_nkwinit
, pk
->pk_nextinit
) == -1)
898 SIMPLEQ_FOREACH(k
, &pk
->pk_keywords
, k_next
) {
899 np
= k
->k_nextparser
;
900 if (np
!= NULL
&& parser_init(np
) == -1)
907 pkw_create(const char *name
, parser_exec_t defexec
, const char *defkey
,
908 const struct kwinst
*kws
, size_t nkw
, struct parser
*defnext
)
912 if ((pk
= calloc(1, sizeof(*pk
))) == NULL
)
915 pk
->pk_parser
.p_methods
= &pkw_methods
;
916 pk
->pk_parser
.p_exec
= defexec
;
917 pk
->pk_parser
.p_name
= name
;
919 SIMPLEQ_INIT(&pk
->pk_keywords
);
921 if (pkw_setwords(pk
, defexec
, defkey
, kws
, nkw
, defnext
) == -1)
931 parse(int argc
, char **argv
, const struct parser
*p0
, struct match
*matches
,
932 size_t *nmatch
, int *narg
)
935 struct match
*lastm
= NULL
, *m
= matches
;
936 const struct parser
*p
= p0
;
938 for (i
= 0; i
< argc
&& p
!= NULL
; i
++) {
939 if ((size_t)(m
- matches
) >= *nmatch
) {
944 rc
= (*p
->p_methods
->pm_match
)(p
, lastm
, m
, i
, argv
[i
]);
950 for (; (size_t)(m
- matches
) < *nmatch
&& p
!= NULL
; ) {
951 rc
= (*p
->p_methods
->pm_match
)(p
, lastm
, m
, i
, NULL
);
958 *nmatch
= m
- matches
;
964 matches_exec(const struct match
*matches
, prop_dictionary_t oenv
, size_t nmatch
)
968 const struct match
*m
;
972 for (i
= 0; i
< nmatch
; i
++) {
974 dbg_warnx("%s.%d: i %zu", __func__
, __LINE__
, i
);
975 pexec
= (m
->m_parser
->p_exec
!= NULL
)
976 ? m
->m_parser
->p_exec
: m
->m_exec
;
979 dbg_warnx("%s.%d: m->m_parser->p_name %s", __func__
, __LINE__
,
980 m
->m_parser
->p_name
);
981 d
= prop_dictionary_augment(m
->m_env
, oenv
);
982 rc
= (*pexec
)(d
, oenv
);
983 prop_object_release((prop_object_t
)d
);
991 parser_init(struct parser
*p
)
993 if (p
->p_initialized
)
995 p
->p_initialized
= true;
996 if (p
->p_methods
->pm_init
== NULL
)
998 return (*p
->p_methods
->pm_init
)(p
);