1 /* Support routines for the various generation passes.
2 Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GCC is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to the Free
18 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
27 #include "gensupport.h"
30 /* In case some macros used by files we include need it, define this here. */
35 static struct obstack obstack
;
36 struct obstack
*rtl_obstack
= &obstack
;
38 static int sequence_num
;
41 static int predicable_default
;
42 static const char *predicable_true
;
43 static const char *predicable_false
;
45 static htab_t condition_table
;
47 static char *base_dir
= NULL
;
49 /* We initially queue all patterns, process the define_insn and
50 define_cond_exec patterns, then return them one at a time. */
57 struct queue_elem
*next
;
60 static struct queue_elem
*define_attr_queue
;
61 static struct queue_elem
**define_attr_tail
= &define_attr_queue
;
62 static struct queue_elem
*define_insn_queue
;
63 static struct queue_elem
**define_insn_tail
= &define_insn_queue
;
64 static struct queue_elem
*define_cond_exec_queue
;
65 static struct queue_elem
**define_cond_exec_tail
= &define_cond_exec_queue
;
66 static struct queue_elem
*other_queue
;
67 static struct queue_elem
**other_tail
= &other_queue
;
69 static void queue_pattern
PARAMS ((rtx
, struct queue_elem
***,
72 /* Current maximum length of directory names in the search path
73 for include files. (Altered as we get more of them.) */
75 size_t max_include_len
;
79 struct file_name_list
*next
;
83 struct file_name_list
*first_dir_md_include
= 0; /* First dir to search */
84 /* First dir to search for <file> */
85 struct file_name_list
*first_bracket_include
= 0;
86 struct file_name_list
*last_dir_md_include
= 0; /* Last in chain */
88 static void remove_constraints
PARAMS ((rtx
));
89 static void process_rtx
PARAMS ((rtx
, int));
91 static int is_predicable
PARAMS ((struct queue_elem
*));
92 static void identify_predicable_attribute
PARAMS ((void));
93 static int n_alternatives
PARAMS ((const char *));
94 static void collect_insn_data
PARAMS ((rtx
, int *, int *));
95 static rtx alter_predicate_for_insn
PARAMS ((rtx
, int, int, int));
96 static const char *alter_test_for_insn
PARAMS ((struct queue_elem
*,
97 struct queue_elem
*));
98 static char *shift_output_template
PARAMS ((char *, const char *, int));
99 static const char *alter_output_for_insn
PARAMS ((struct queue_elem
*,
102 static void process_one_cond_exec
PARAMS ((struct queue_elem
*));
103 static void process_define_cond_exec
PARAMS ((void));
104 static void process_include
PARAMS ((rtx
, int));
105 static char *save_string
PARAMS ((const char *, int));
108 message_with_line
VPARAMS ((int lineno
, const char *msg
, ...))
111 VA_FIXEDARG (ap
, int, lineno
);
112 VA_FIXEDARG (ap
, const char *, msg
);
114 fprintf (stderr
, "%s:%d: ", read_rtx_filename
, lineno
);
115 vfprintf (stderr
, msg
, ap
);
116 fputc ('\n', stderr
);
121 /* Make a version of gen_rtx_CONST_INT so that GEN_INT can be used in
122 the gensupport programs. */
125 gen_rtx_CONST_INT (mode
, arg
)
126 enum machine_mode mode ATTRIBUTE_UNUSED
;
129 rtx rt
= rtx_alloc (CONST_INT
);
135 /* Queue PATTERN on LIST_TAIL. */
138 queue_pattern (pattern
, list_tail
, filename
, lineno
)
140 struct queue_elem
***list_tail
;
141 const char *filename
;
144 struct queue_elem
*e
= (struct queue_elem
*) xmalloc (sizeof (*e
));
146 e
->filename
= filename
;
150 *list_tail
= &e
->next
;
153 /* Recursively remove constraints from an rtx. */
156 remove_constraints (part
)
160 const char *format_ptr
;
165 if (GET_CODE (part
) == MATCH_OPERAND
)
167 else if (GET_CODE (part
) == MATCH_SCRATCH
)
170 format_ptr
= GET_RTX_FORMAT (GET_CODE (part
));
172 for (i
= 0; i
< GET_RTX_LENGTH (GET_CODE (part
)); i
++)
173 switch (*format_ptr
++)
177 remove_constraints (XEXP (part
, i
));
180 if (XVEC (part
, i
) != NULL
)
181 for (j
= 0; j
< XVECLEN (part
, i
); j
++)
182 remove_constraints (XVECEXP (part
, i
, j
));
187 /* Process an include file assuming that it lives in gcc/config/{target}/
188 if the include looks like (include "file"). */
191 process_include (desc
, lineno
)
195 const char *filename
= XSTR (desc
, 0);
196 const char *old_filename
;
201 /* If specified file name is absolute, skip the include stack. */
202 if (! IS_ABSOLUTE_PATHNAME (filename
))
204 struct file_name_list
*stackp
;
206 /* Search directory path, trying to open the file. */
207 for (stackp
= first_dir_md_include
; stackp
; stackp
= stackp
->next
)
209 static const char sep
[2] = { DIR_SEPARATOR
, '\0' };
211 pathname
= concat (stackp
->fname
, sep
, filename
, NULL
);
212 input_file
= fopen (pathname
, "r");
213 if (input_file
!= NULL
)
220 pathname
= concat (base_dir
, filename
, NULL
);
222 pathname
= xstrdup (filename
);
223 input_file
= fopen (pathname
, "r");
224 if (input_file
== NULL
)
227 message_with_line (lineno
, "include file `%s' not found", filename
);
233 /* Save old cursor; setup new for the new file. Note that "lineno" the
234 argument to this function is the beginning of the include statement,
235 while read_rtx_lineno has already been advanced. */
236 old_filename
= read_rtx_filename
;
237 old_lineno
= read_rtx_lineno
;
238 read_rtx_filename
= pathname
;
241 /* Read the entire file. */
247 c
= read_skip_spaces (input_file
);
251 ungetc (c
, input_file
);
252 lineno
= read_rtx_lineno
;
253 desc
= read_rtx (input_file
);
254 process_rtx (desc
, lineno
);
257 /* Do not free pathname. It is attached to the various rtx queue
260 read_rtx_filename
= old_filename
;
261 read_rtx_lineno
= old_lineno
;
266 /* Process a top level rtx in some way, queueing as appropriate. */
269 process_rtx (desc
, lineno
)
273 switch (GET_CODE (desc
))
276 queue_pattern (desc
, &define_insn_tail
, read_rtx_filename
, lineno
);
279 case DEFINE_COND_EXEC
:
280 queue_pattern (desc
, &define_cond_exec_tail
, read_rtx_filename
, lineno
);
284 queue_pattern (desc
, &define_attr_tail
, read_rtx_filename
, lineno
);
288 process_include (desc
, lineno
);
291 case DEFINE_INSN_AND_SPLIT
:
293 const char *split_cond
;
298 /* Create a split with values from the insn_and_split. */
299 split
= rtx_alloc (DEFINE_SPLIT
);
301 i
= XVECLEN (desc
, 1);
302 XVEC (split
, 0) = rtvec_alloc (i
);
305 XVECEXP (split
, 0, i
) = copy_rtx (XVECEXP (desc
, 1, i
));
306 remove_constraints (XVECEXP (split
, 0, i
));
309 /* If the split condition starts with "&&", append it to the
310 insn condition to create the new split condition. */
311 split_cond
= XSTR (desc
, 4);
312 if (split_cond
[0] == '&' && split_cond
[1] == '&')
313 split_cond
= concat (XSTR (desc
, 2), split_cond
, NULL
);
314 XSTR (split
, 1) = split_cond
;
315 XVEC (split
, 2) = XVEC (desc
, 5);
316 XSTR (split
, 3) = XSTR (desc
, 6);
318 /* Fix up the DEFINE_INSN. */
319 attr
= XVEC (desc
, 7);
320 PUT_CODE (desc
, DEFINE_INSN
);
321 XVEC (desc
, 4) = attr
;
324 queue_pattern (desc
, &define_insn_tail
, read_rtx_filename
, lineno
);
325 queue_pattern (split
, &other_tail
, read_rtx_filename
, lineno
);
330 queue_pattern (desc
, &other_tail
, read_rtx_filename
, lineno
);
335 /* Return true if attribute PREDICABLE is true for ELEM, which holds
340 struct queue_elem
*elem
;
342 rtvec vec
= XVEC (elem
->data
, 4);
347 return predicable_default
;
349 for (i
= GET_NUM_ELEM (vec
) - 1; i
>= 0; --i
)
351 rtx sub
= RTVEC_ELT (vec
, i
);
352 switch (GET_CODE (sub
))
355 if (strcmp (XSTR (sub
, 0), "predicable") == 0)
357 value
= XSTR (sub
, 1);
362 case SET_ATTR_ALTERNATIVE
:
363 if (strcmp (XSTR (sub
, 0), "predicable") == 0)
365 message_with_line (elem
->lineno
,
366 "multiple alternatives for `predicable'");
373 if (GET_CODE (SET_DEST (sub
)) != ATTR
374 || strcmp (XSTR (SET_DEST (sub
), 0), "predicable") != 0)
377 if (GET_CODE (sub
) == CONST_STRING
)
379 value
= XSTR (sub
, 0);
383 /* ??? It would be possible to handle this if we really tried.
384 It's not easy though, and I'm not going to bother until it
385 really proves necessary. */
386 message_with_line (elem
->lineno
,
387 "non-constant value for `predicable'");
396 return predicable_default
;
399 /* Verify that predicability does not vary on the alternative. */
400 /* ??? It should be possible to handle this by simply eliminating
401 the non-predicable alternatives from the insn. FRV would like
402 to do this. Delay this until we've got the basics solid. */
403 if (strchr (value
, ',') != NULL
)
405 message_with_line (elem
->lineno
,
406 "multiple alternatives for `predicable'");
411 /* Find out which value we're looking at. */
412 if (strcmp (value
, predicable_true
) == 0)
414 if (strcmp (value
, predicable_false
) == 0)
417 message_with_line (elem
->lineno
,
418 "unknown value `%s' for `predicable' attribute",
424 /* Examine the attribute "predicable"; discover its boolean values
428 identify_predicable_attribute ()
430 struct queue_elem
*elem
;
431 char *p_true
, *p_false
;
434 /* Look for the DEFINE_ATTR for `predicable', which must exist. */
435 for (elem
= define_attr_queue
; elem
; elem
= elem
->next
)
436 if (strcmp (XSTR (elem
->data
, 0), "predicable") == 0)
439 message_with_line (define_cond_exec_queue
->lineno
,
440 "attribute `predicable' not defined");
445 value
= XSTR (elem
->data
, 1);
446 p_false
= xstrdup (value
);
447 p_true
= strchr (p_false
, ',');
448 if (p_true
== NULL
|| strchr (++p_true
, ',') != NULL
)
450 message_with_line (elem
->lineno
,
451 "attribute `predicable' is not a boolean");
457 predicable_true
= p_true
;
458 predicable_false
= p_false
;
460 switch (GET_CODE (XEXP (elem
->data
, 2)))
463 value
= XSTR (XEXP (elem
->data
, 2), 0);
467 message_with_line (elem
->lineno
,
468 "attribute `predicable' cannot be const");
473 message_with_line (elem
->lineno
,
474 "attribute `predicable' must have a constant default");
479 if (strcmp (value
, p_true
) == 0)
480 predicable_default
= 1;
481 else if (strcmp (value
, p_false
) == 0)
482 predicable_default
= 0;
485 message_with_line (elem
->lineno
,
486 "unknown value `%s' for `predicable' attribute",
492 /* Return the number of alternatives in constraint S. */
507 /* Determine how many alternatives there are in INSN, and how many
511 collect_insn_data (pattern
, palt
, pmax
)
519 code
= GET_CODE (pattern
);
523 i
= n_alternatives (XSTR (pattern
, 2));
524 *palt
= (i
> *palt
? i
: *palt
);
531 i
= XINT (pattern
, 0);
540 fmt
= GET_RTX_FORMAT (code
);
541 len
= GET_RTX_LENGTH (code
);
542 for (i
= 0; i
< len
; i
++)
547 collect_insn_data (XEXP (pattern
, i
), palt
, pmax
);
551 if (XVEC (pattern
, i
) == NULL
)
555 for (j
= XVECLEN (pattern
, i
) - 1; j
>= 0; --j
)
556 collect_insn_data (XVECEXP (pattern
, i
, j
), palt
, pmax
);
559 case 'i': case 'w': case '0': case 's': case 'S': case 'T':
569 alter_predicate_for_insn (pattern
, alt
, max_op
, lineno
)
571 int alt
, max_op
, lineno
;
577 code
= GET_CODE (pattern
);
582 const char *c
= XSTR (pattern
, 2);
584 if (n_alternatives (c
) != 1)
586 message_with_line (lineno
,
587 "too many alternatives for operand %d",
593 /* Replicate C as needed to fill out ALT alternatives. */
594 if (c
&& *c
&& alt
> 1)
596 size_t c_len
= strlen (c
);
597 size_t len
= alt
* (c_len
+ 1);
598 char *new_c
= (char *) xmalloc (len
);
600 memcpy (new_c
, c
, c_len
);
601 for (i
= 1; i
< alt
; ++i
)
603 new_c
[i
* (c_len
+ 1) - 1] = ',';
604 memcpy (&new_c
[i
* (c_len
+ 1)], c
, c_len
);
606 new_c
[len
- 1] = '\0';
607 XSTR (pattern
, 2) = new_c
;
616 XINT (pattern
, 0) += max_op
;
623 fmt
= GET_RTX_FORMAT (code
);
624 len
= GET_RTX_LENGTH (code
);
625 for (i
= 0; i
< len
; i
++)
632 r
= alter_predicate_for_insn (XEXP (pattern
, i
), alt
,
639 for (j
= XVECLEN (pattern
, i
) - 1; j
>= 0; --j
)
641 r
= alter_predicate_for_insn (XVECEXP (pattern
, i
, j
),
642 alt
, max_op
, lineno
);
648 case 'i': case 'w': case '0': case 's':
660 alter_test_for_insn (ce_elem
, insn_elem
)
661 struct queue_elem
*ce_elem
, *insn_elem
;
663 const char *ce_test
, *insn_test
;
665 ce_test
= XSTR (ce_elem
->data
, 1);
666 insn_test
= XSTR (insn_elem
->data
, 2);
667 if (!ce_test
|| *ce_test
== '\0')
669 if (!insn_test
|| *insn_test
== '\0')
672 return concat ("(", ce_test
, ") && (", insn_test
, ")", NULL
);
675 /* Adjust all of the operand numbers in OLD to match the shift they'll
676 get from an operand displacement of DISP. Return a pointer after the
680 shift_output_template (new, old
, disp
)
692 if (ISDIGIT ((unsigned char) c
))
694 else if (ISALPHA (c
))
707 alter_output_for_insn (ce_elem
, insn_elem
, alt
, max_op
)
708 struct queue_elem
*ce_elem
, *insn_elem
;
711 const char *ce_out
, *insn_out
;
713 size_t len
, ce_len
, insn_len
;
715 /* ??? Could coordinate with genoutput to not duplicate code here. */
717 ce_out
= XSTR (ce_elem
->data
, 2);
718 insn_out
= XTMPL (insn_elem
->data
, 3);
719 if (!ce_out
|| *ce_out
== '\0')
722 ce_len
= strlen (ce_out
);
723 insn_len
= strlen (insn_out
);
725 if (*insn_out
== '*')
726 /* You must take care of the predicate yourself. */
729 if (*insn_out
== '@')
731 len
= (ce_len
+ 1) * alt
+ insn_len
+ 1;
732 p
= new = xmalloc (len
);
738 while (ISSPACE ((unsigned char) *insn_out
));
740 if (*insn_out
!= '#')
742 p
= shift_output_template (p
, ce_out
, max_op
);
748 while (*insn_out
&& *insn_out
!= '\n');
755 len
= ce_len
+ 1 + insn_len
+ 1;
758 p
= shift_output_template (new, ce_out
, max_op
);
760 memcpy (p
, insn_out
, insn_len
+ 1);
766 /* Replicate insns as appropriate for the given DEFINE_COND_EXEC. */
769 process_one_cond_exec (ce_elem
)
770 struct queue_elem
*ce_elem
;
772 struct queue_elem
*insn_elem
;
773 for (insn_elem
= define_insn_queue
; insn_elem
; insn_elem
= insn_elem
->next
)
775 int alternatives
, max_operand
;
776 rtx pred
, insn
, pattern
;
778 if (! is_predicable (insn_elem
))
783 collect_insn_data (insn_elem
->data
, &alternatives
, &max_operand
);
786 if (XVECLEN (ce_elem
->data
, 0) != 1)
788 message_with_line (ce_elem
->lineno
,
789 "too many patterns in predicate");
794 pred
= copy_rtx (XVECEXP (ce_elem
->data
, 0, 0));
795 pred
= alter_predicate_for_insn (pred
, alternatives
, max_operand
,
800 /* Construct a new pattern for the new insn. */
801 insn
= copy_rtx (insn_elem
->data
);
803 pattern
= rtx_alloc (COND_EXEC
);
804 XEXP (pattern
, 0) = pred
;
805 if (XVECLEN (insn
, 1) == 1)
807 XEXP (pattern
, 1) = XVECEXP (insn
, 1, 0);
808 XVECEXP (insn
, 1, 0) = pattern
;
809 PUT_NUM_ELEM (XVEC (insn
, 1), 1);
813 XEXP (pattern
, 1) = rtx_alloc (PARALLEL
);
814 XVEC (XEXP (pattern
, 1), 0) = XVEC (insn
, 1);
815 XVEC (insn
, 1) = rtvec_alloc (1);
816 XVECEXP (insn
, 1, 0) = pattern
;
819 XSTR (insn
, 2) = alter_test_for_insn (ce_elem
, insn_elem
);
820 XTMPL (insn
, 3) = alter_output_for_insn (ce_elem
, insn_elem
,
821 alternatives
, max_operand
);
823 /* ??? Set `predicable' to false. Not crucial since it's really
824 only used here, and we won't reprocess this new pattern. */
826 /* Put the new pattern on the `other' list so that it
827 (a) is not reprocessed by other define_cond_exec patterns
828 (b) appears after all normal define_insn patterns.
830 ??? B is debatable. If one has normal insns that match
831 cond_exec patterns, they will be preferred over these
832 generated patterns. Whether this matters in practice, or if
833 it's a good thing, or whether we should thread these new
834 patterns into the define_insn chain just after their generator
835 is something we'll have to experiment with. */
837 queue_pattern (insn
, &other_tail
, insn_elem
->filename
,
842 /* If we have any DEFINE_COND_EXEC patterns, expand the DEFINE_INSN
843 patterns appropriately. */
846 process_define_cond_exec ()
848 struct queue_elem
*elem
;
850 identify_predicable_attribute ();
854 for (elem
= define_cond_exec_queue
; elem
; elem
= elem
->next
)
855 process_one_cond_exec (elem
);
863 register char *result
= xmalloc (len
+ 1);
865 memcpy (result
, s
, len
);
871 /* The entry point for initializing the reader. */
874 init_md_reader_args (argc
, argv
)
879 const char *in_fname
;
883 for (i
= 1; i
< argc
; i
++)
885 if (argv
[i
][0] != '-')
887 if (in_fname
== NULL
)
895 case 'I': /* Add directory to path for includes. */
897 struct file_name_list
*dirtmp
;
899 dirtmp
= (struct file_name_list
*)
900 xmalloc (sizeof (struct file_name_list
));
901 dirtmp
->next
= 0; /* New one goes on the end */
902 if (first_dir_md_include
== 0)
903 first_dir_md_include
= dirtmp
;
905 last_dir_md_include
->next
= dirtmp
;
906 last_dir_md_include
= dirtmp
; /* Tail follows the last one */
907 if (argv
[i
][1] == 'I' && argv
[i
][2] != 0)
908 dirtmp
->fname
= argv
[i
] + 2;
909 else if (i
+ 1 == argc
)
910 fatal ("directory name missing after -I option");
912 dirtmp
->fname
= argv
[++i
];
913 if (strlen (dirtmp
->fname
) > max_include_len
)
914 max_include_len
= strlen (dirtmp
->fname
);
918 fatal ("invalid option `%s'", argv
[i
]);
923 return init_md_reader (in_fname
);
926 /* The entry point for initializing the reader. */
929 init_md_reader (filename
)
930 const char *filename
;
937 lastsl
= strrchr (filename
, '/');
939 base_dir
= save_string (filename
, lastsl
- filename
+ 1 );
941 read_rtx_filename
= filename
;
942 input_file
= fopen (filename
, "r");
946 return FATAL_EXIT_CODE
;
949 /* Initialize the table of insn conditions. */
950 condition_table
= htab_create (n_insn_conditions
,
951 hash_c_test
, cmp_c_test
, NULL
);
953 for (i
= 0; i
< n_insn_conditions
; i
++)
954 *(htab_find_slot (condition_table
, (PTR
) &insn_conditions
[i
], INSERT
))
955 = (PTR
) &insn_conditions
[i
];
957 obstack_init (rtl_obstack
);
961 /* Read the entire file. */
967 c
= read_skip_spaces (input_file
);
971 ungetc (c
, input_file
);
972 lineno
= read_rtx_lineno
;
973 desc
= read_rtx (input_file
);
974 process_rtx (desc
, lineno
);
978 /* Process define_cond_exec patterns. */
979 if (define_cond_exec_queue
!= NULL
)
980 process_define_cond_exec ();
982 return errors
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
985 /* The entry point for reading a single rtx from an md file. */
988 read_md_rtx (lineno
, seqnr
)
992 struct queue_elem
**queue
, *elem
;
997 /* Read all patterns from a given queue before moving on to the next. */
998 if (define_attr_queue
!= NULL
)
999 queue
= &define_attr_queue
;
1000 else if (define_insn_queue
!= NULL
)
1001 queue
= &define_insn_queue
;
1002 else if (other_queue
!= NULL
)
1003 queue
= &other_queue
;
1008 *queue
= elem
->next
;
1010 read_rtx_filename
= elem
->filename
;
1011 *lineno
= elem
->lineno
;
1012 *seqnr
= sequence_num
;
1016 /* Discard insn patterns which we know can never match (because
1017 their C test is provably always false). If insn_elision is
1018 false, our caller needs to see all the patterns. Note that the
1019 elided patterns are never counted by the sequence numbering; it
1020 it is the caller's responsibility, when insn_elision is false, not
1021 to use elided pattern numbers for anything. */
1022 switch (GET_CODE (desc
))
1026 if (maybe_eval_c_test (XSTR (desc
, 2)) != 0)
1028 else if (insn_elision
)
1033 case DEFINE_PEEPHOLE
:
1034 case DEFINE_PEEPHOLE2
:
1035 if (maybe_eval_c_test (XSTR (desc
, 1)) != 0)
1037 else if (insn_elision
)
1048 /* Helper functions for insn elision. */
1050 /* Compute a hash function of a c_test structure, which is keyed
1051 by its ->expr field. */
1056 const struct c_test
*a
= (const struct c_test
*) x
;
1057 const unsigned char *base
, *s
= (const unsigned char *) a
->expr
;
1065 while ((c
= *s
++) != '\0')
1067 hash
+= c
+ (c
<< 17);
1072 hash
+= len
+ (len
<< 17);
1078 /* Compare two c_test expression structures. */
1084 const struct c_test
*a
= (const struct c_test
*) x
;
1085 const struct c_test
*b
= (const struct c_test
*) y
;
1087 return !strcmp (a
->expr
, b
->expr
);
1090 /* Given a string representing a C test expression, look it up in the
1091 condition_table and report whether or not its value is known
1092 at compile time. Returns a tristate: 1 for known true, 0 for
1093 known false, -1 for unknown. */
1095 maybe_eval_c_test (expr
)
1098 const struct c_test
*test
;
1099 struct c_test dummy
;
1104 if (insn_elision_unavailable
)
1108 test
= (const struct c_test
*) htab_find (condition_table
, &dummy
);
1115 /* Given a string, return the number of comma-separated elements in it.
1116 Return 0 for the null string. */
1126 for (n
= 1; *s
; s
++)
1133 /* Given a pointer to a (char *), return a pointer to the beginning of the
1134 next comma-separated element in the string. Advance the pointer given
1135 to the end of that element. Return NULL if at end of string. Caller
1136 is responsible for copying the string if necessary. White space between
1137 a comma and an element is ignored. */
1140 scan_comma_elt (pstr
)
1144 const char *p
= *pstr
;
1156 while (*p
!= ',' && *p
!= '\0')