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
23 #include "coretypes.h"
29 #include "gensupport.h"
32 /* In case some macros used by files we include need it, define this here. */
37 static struct obstack obstack
;
38 struct obstack
*rtl_obstack
= &obstack
;
40 static int sequence_num
;
43 static int predicable_default
;
44 static const char *predicable_true
;
45 static const char *predicable_false
;
47 static htab_t condition_table
;
49 static char *base_dir
= NULL
;
51 /* We initially queue all patterns, process the define_insn and
52 define_cond_exec patterns, then return them one at a time. */
59 struct queue_elem
*next
;
62 static struct queue_elem
*define_attr_queue
;
63 static struct queue_elem
**define_attr_tail
= &define_attr_queue
;
64 static struct queue_elem
*define_insn_queue
;
65 static struct queue_elem
**define_insn_tail
= &define_insn_queue
;
66 static struct queue_elem
*define_cond_exec_queue
;
67 static struct queue_elem
**define_cond_exec_tail
= &define_cond_exec_queue
;
68 static struct queue_elem
*other_queue
;
69 static struct queue_elem
**other_tail
= &other_queue
;
71 static void queue_pattern
PARAMS ((rtx
, struct queue_elem
***,
74 /* Current maximum length of directory names in the search path
75 for include files. (Altered as we get more of them.) */
77 size_t max_include_len
;
81 struct file_name_list
*next
;
85 struct file_name_list
*first_dir_md_include
= 0; /* First dir to search */
86 /* First dir to search for <file> */
87 struct file_name_list
*first_bracket_include
= 0;
88 struct file_name_list
*last_dir_md_include
= 0; /* Last in chain */
90 static void remove_constraints
PARAMS ((rtx
));
91 static void process_rtx
PARAMS ((rtx
, int));
93 static int is_predicable
PARAMS ((struct queue_elem
*));
94 static void identify_predicable_attribute
PARAMS ((void));
95 static int n_alternatives
PARAMS ((const char *));
96 static void collect_insn_data
PARAMS ((rtx
, int *, int *));
97 static rtx alter_predicate_for_insn
PARAMS ((rtx
, int, int, int));
98 static const char *alter_test_for_insn
PARAMS ((struct queue_elem
*,
99 struct queue_elem
*));
100 static char *shift_output_template
PARAMS ((char *, const char *, int));
101 static const char *alter_output_for_insn
PARAMS ((struct queue_elem
*,
104 static void process_one_cond_exec
PARAMS ((struct queue_elem
*));
105 static void process_define_cond_exec
PARAMS ((void));
106 static void process_include
PARAMS ((rtx
, int));
107 static char *save_string
PARAMS ((const char *, int));
110 message_with_line
VPARAMS ((int lineno
, const char *msg
, ...))
113 VA_FIXEDARG (ap
, int, lineno
);
114 VA_FIXEDARG (ap
, const char *, msg
);
116 fprintf (stderr
, "%s:%d: ", read_rtx_filename
, lineno
);
117 vfprintf (stderr
, msg
, ap
);
118 fputc ('\n', stderr
);
123 /* Make a version of gen_rtx_CONST_INT so that GEN_INT can be used in
124 the gensupport programs. */
127 gen_rtx_CONST_INT (mode
, arg
)
128 enum machine_mode mode ATTRIBUTE_UNUSED
;
131 rtx rt
= rtx_alloc (CONST_INT
);
137 /* Queue PATTERN on LIST_TAIL. */
140 queue_pattern (pattern
, list_tail
, filename
, lineno
)
142 struct queue_elem
***list_tail
;
143 const char *filename
;
146 struct queue_elem
*e
= (struct queue_elem
*) xmalloc (sizeof (*e
));
148 e
->filename
= filename
;
152 *list_tail
= &e
->next
;
155 /* Recursively remove constraints from an rtx. */
158 remove_constraints (part
)
162 const char *format_ptr
;
167 if (GET_CODE (part
) == MATCH_OPERAND
)
169 else if (GET_CODE (part
) == MATCH_SCRATCH
)
172 format_ptr
= GET_RTX_FORMAT (GET_CODE (part
));
174 for (i
= 0; i
< GET_RTX_LENGTH (GET_CODE (part
)); i
++)
175 switch (*format_ptr
++)
179 remove_constraints (XEXP (part
, i
));
182 if (XVEC (part
, i
) != NULL
)
183 for (j
= 0; j
< XVECLEN (part
, i
); j
++)
184 remove_constraints (XVECEXP (part
, i
, j
));
189 /* Process an include file assuming that it lives in gcc/config/{target}/
190 if the include looks like (include "file"). */
193 process_include (desc
, lineno
)
197 const char *filename
= XSTR (desc
, 0);
198 const char *old_filename
;
203 /* If specified file name is absolute, skip the include stack. */
204 if (! IS_ABSOLUTE_PATHNAME (filename
))
206 struct file_name_list
*stackp
;
208 /* Search directory path, trying to open the file. */
209 for (stackp
= first_dir_md_include
; stackp
; stackp
= stackp
->next
)
211 static const char sep
[2] = { DIR_SEPARATOR
, '\0' };
213 pathname
= concat (stackp
->fname
, sep
, filename
, NULL
);
214 input_file
= fopen (pathname
, "r");
215 if (input_file
!= NULL
)
222 pathname
= concat (base_dir
, filename
, NULL
);
224 pathname
= xstrdup (filename
);
225 input_file
= fopen (pathname
, "r");
226 if (input_file
== NULL
)
229 message_with_line (lineno
, "include file `%s' not found", filename
);
235 /* Save old cursor; setup new for the new file. Note that "lineno" the
236 argument to this function is the beginning of the include statement,
237 while read_rtx_lineno has already been advanced. */
238 old_filename
= read_rtx_filename
;
239 old_lineno
= read_rtx_lineno
;
240 read_rtx_filename
= pathname
;
243 /* Read the entire file. */
249 c
= read_skip_spaces (input_file
);
253 ungetc (c
, input_file
);
254 lineno
= read_rtx_lineno
;
255 desc
= read_rtx (input_file
);
256 process_rtx (desc
, lineno
);
259 /* Do not free pathname. It is attached to the various rtx queue
262 read_rtx_filename
= old_filename
;
263 read_rtx_lineno
= old_lineno
;
268 /* Process a top level rtx in some way, queueing as appropriate. */
271 process_rtx (desc
, lineno
)
275 switch (GET_CODE (desc
))
278 queue_pattern (desc
, &define_insn_tail
, read_rtx_filename
, lineno
);
281 case DEFINE_COND_EXEC
:
282 queue_pattern (desc
, &define_cond_exec_tail
, read_rtx_filename
, lineno
);
286 queue_pattern (desc
, &define_attr_tail
, read_rtx_filename
, lineno
);
290 process_include (desc
, lineno
);
293 case DEFINE_INSN_AND_SPLIT
:
295 const char *split_cond
;
300 /* Create a split with values from the insn_and_split. */
301 split
= rtx_alloc (DEFINE_SPLIT
);
303 i
= XVECLEN (desc
, 1);
304 XVEC (split
, 0) = rtvec_alloc (i
);
307 XVECEXP (split
, 0, i
) = copy_rtx (XVECEXP (desc
, 1, i
));
308 remove_constraints (XVECEXP (split
, 0, i
));
311 /* If the split condition starts with "&&", append it to the
312 insn condition to create the new split condition. */
313 split_cond
= XSTR (desc
, 4);
314 if (split_cond
[0] == '&' && split_cond
[1] == '&')
315 split_cond
= concat (XSTR (desc
, 2), split_cond
, NULL
);
316 XSTR (split
, 1) = split_cond
;
317 XVEC (split
, 2) = XVEC (desc
, 5);
318 XSTR (split
, 3) = XSTR (desc
, 6);
320 /* Fix up the DEFINE_INSN. */
321 attr
= XVEC (desc
, 7);
322 PUT_CODE (desc
, DEFINE_INSN
);
323 XVEC (desc
, 4) = attr
;
326 queue_pattern (desc
, &define_insn_tail
, read_rtx_filename
, lineno
);
327 queue_pattern (split
, &other_tail
, read_rtx_filename
, lineno
);
332 queue_pattern (desc
, &other_tail
, read_rtx_filename
, lineno
);
337 /* Return true if attribute PREDICABLE is true for ELEM, which holds
342 struct queue_elem
*elem
;
344 rtvec vec
= XVEC (elem
->data
, 4);
349 return predicable_default
;
351 for (i
= GET_NUM_ELEM (vec
) - 1; i
>= 0; --i
)
353 rtx sub
= RTVEC_ELT (vec
, i
);
354 switch (GET_CODE (sub
))
357 if (strcmp (XSTR (sub
, 0), "predicable") == 0)
359 value
= XSTR (sub
, 1);
364 case SET_ATTR_ALTERNATIVE
:
365 if (strcmp (XSTR (sub
, 0), "predicable") == 0)
367 message_with_line (elem
->lineno
,
368 "multiple alternatives for `predicable'");
375 if (GET_CODE (SET_DEST (sub
)) != ATTR
376 || strcmp (XSTR (SET_DEST (sub
), 0), "predicable") != 0)
379 if (GET_CODE (sub
) == CONST_STRING
)
381 value
= XSTR (sub
, 0);
385 /* ??? It would be possible to handle this if we really tried.
386 It's not easy though, and I'm not going to bother until it
387 really proves necessary. */
388 message_with_line (elem
->lineno
,
389 "non-constant value for `predicable'");
398 return predicable_default
;
401 /* Verify that predicability does not vary on the alternative. */
402 /* ??? It should be possible to handle this by simply eliminating
403 the non-predicable alternatives from the insn. FRV would like
404 to do this. Delay this until we've got the basics solid. */
405 if (strchr (value
, ',') != NULL
)
407 message_with_line (elem
->lineno
,
408 "multiple alternatives for `predicable'");
413 /* Find out which value we're looking at. */
414 if (strcmp (value
, predicable_true
) == 0)
416 if (strcmp (value
, predicable_false
) == 0)
419 message_with_line (elem
->lineno
,
420 "unknown value `%s' for `predicable' attribute",
426 /* Examine the attribute "predicable"; discover its boolean values
430 identify_predicable_attribute ()
432 struct queue_elem
*elem
;
433 char *p_true
, *p_false
;
436 /* Look for the DEFINE_ATTR for `predicable', which must exist. */
437 for (elem
= define_attr_queue
; elem
; elem
= elem
->next
)
438 if (strcmp (XSTR (elem
->data
, 0), "predicable") == 0)
441 message_with_line (define_cond_exec_queue
->lineno
,
442 "attribute `predicable' not defined");
447 value
= XSTR (elem
->data
, 1);
448 p_false
= xstrdup (value
);
449 p_true
= strchr (p_false
, ',');
450 if (p_true
== NULL
|| strchr (++p_true
, ',') != NULL
)
452 message_with_line (elem
->lineno
,
453 "attribute `predicable' is not a boolean");
459 predicable_true
= p_true
;
460 predicable_false
= p_false
;
462 switch (GET_CODE (XEXP (elem
->data
, 2)))
465 value
= XSTR (XEXP (elem
->data
, 2), 0);
469 message_with_line (elem
->lineno
,
470 "attribute `predicable' cannot be const");
475 message_with_line (elem
->lineno
,
476 "attribute `predicable' must have a constant default");
481 if (strcmp (value
, p_true
) == 0)
482 predicable_default
= 1;
483 else if (strcmp (value
, p_false
) == 0)
484 predicable_default
= 0;
487 message_with_line (elem
->lineno
,
488 "unknown value `%s' for `predicable' attribute",
494 /* Return the number of alternatives in constraint S. */
509 /* Determine how many alternatives there are in INSN, and how many
513 collect_insn_data (pattern
, palt
, pmax
)
521 code
= GET_CODE (pattern
);
525 i
= n_alternatives (XSTR (pattern
, 2));
526 *palt
= (i
> *palt
? i
: *palt
);
533 i
= XINT (pattern
, 0);
542 fmt
= GET_RTX_FORMAT (code
);
543 len
= GET_RTX_LENGTH (code
);
544 for (i
= 0; i
< len
; i
++)
549 collect_insn_data (XEXP (pattern
, i
), palt
, pmax
);
553 if (XVEC (pattern
, i
) == NULL
)
557 for (j
= XVECLEN (pattern
, i
) - 1; j
>= 0; --j
)
558 collect_insn_data (XVECEXP (pattern
, i
, j
), palt
, pmax
);
561 case 'i': case 'w': case '0': case 's': case 'S': case 'T':
571 alter_predicate_for_insn (pattern
, alt
, max_op
, lineno
)
573 int alt
, max_op
, lineno
;
579 code
= GET_CODE (pattern
);
584 const char *c
= XSTR (pattern
, 2);
586 if (n_alternatives (c
) != 1)
588 message_with_line (lineno
,
589 "too many alternatives for operand %d",
595 /* Replicate C as needed to fill out ALT alternatives. */
596 if (c
&& *c
&& alt
> 1)
598 size_t c_len
= strlen (c
);
599 size_t len
= alt
* (c_len
+ 1);
600 char *new_c
= (char *) xmalloc (len
);
602 memcpy (new_c
, c
, c_len
);
603 for (i
= 1; i
< alt
; ++i
)
605 new_c
[i
* (c_len
+ 1) - 1] = ',';
606 memcpy (&new_c
[i
* (c_len
+ 1)], c
, c_len
);
608 new_c
[len
- 1] = '\0';
609 XSTR (pattern
, 2) = new_c
;
618 XINT (pattern
, 0) += max_op
;
625 fmt
= GET_RTX_FORMAT (code
);
626 len
= GET_RTX_LENGTH (code
);
627 for (i
= 0; i
< len
; i
++)
634 r
= alter_predicate_for_insn (XEXP (pattern
, i
), alt
,
641 for (j
= XVECLEN (pattern
, i
) - 1; j
>= 0; --j
)
643 r
= alter_predicate_for_insn (XVECEXP (pattern
, i
, j
),
644 alt
, max_op
, lineno
);
650 case 'i': case 'w': case '0': case 's':
662 alter_test_for_insn (ce_elem
, insn_elem
)
663 struct queue_elem
*ce_elem
, *insn_elem
;
665 const char *ce_test
, *insn_test
;
667 ce_test
= XSTR (ce_elem
->data
, 1);
668 insn_test
= XSTR (insn_elem
->data
, 2);
669 if (!ce_test
|| *ce_test
== '\0')
671 if (!insn_test
|| *insn_test
== '\0')
674 return concat ("(", ce_test
, ") && (", insn_test
, ")", NULL
);
677 /* Adjust all of the operand numbers in OLD to match the shift they'll
678 get from an operand displacement of DISP. Return a pointer after the
682 shift_output_template (new, old
, disp
)
694 if (ISDIGIT ((unsigned char) c
))
696 else if (ISALPHA (c
))
709 alter_output_for_insn (ce_elem
, insn_elem
, alt
, max_op
)
710 struct queue_elem
*ce_elem
, *insn_elem
;
713 const char *ce_out
, *insn_out
;
715 size_t len
, ce_len
, insn_len
;
717 /* ??? Could coordinate with genoutput to not duplicate code here. */
719 ce_out
= XSTR (ce_elem
->data
, 2);
720 insn_out
= XTMPL (insn_elem
->data
, 3);
721 if (!ce_out
|| *ce_out
== '\0')
724 ce_len
= strlen (ce_out
);
725 insn_len
= strlen (insn_out
);
727 if (*insn_out
== '*')
728 /* You must take care of the predicate yourself. */
731 if (*insn_out
== '@')
733 len
= (ce_len
+ 1) * alt
+ insn_len
+ 1;
734 p
= new = xmalloc (len
);
740 while (ISSPACE ((unsigned char) *insn_out
));
742 if (*insn_out
!= '#')
744 p
= shift_output_template (p
, ce_out
, max_op
);
750 while (*insn_out
&& *insn_out
!= '\n');
757 len
= ce_len
+ 1 + insn_len
+ 1;
760 p
= shift_output_template (new, ce_out
, max_op
);
762 memcpy (p
, insn_out
, insn_len
+ 1);
768 /* Replicate insns as appropriate for the given DEFINE_COND_EXEC. */
771 process_one_cond_exec (ce_elem
)
772 struct queue_elem
*ce_elem
;
774 struct queue_elem
*insn_elem
;
775 for (insn_elem
= define_insn_queue
; insn_elem
; insn_elem
= insn_elem
->next
)
777 int alternatives
, max_operand
;
778 rtx pred
, insn
, pattern
;
780 if (! is_predicable (insn_elem
))
785 collect_insn_data (insn_elem
->data
, &alternatives
, &max_operand
);
788 if (XVECLEN (ce_elem
->data
, 0) != 1)
790 message_with_line (ce_elem
->lineno
,
791 "too many patterns in predicate");
796 pred
= copy_rtx (XVECEXP (ce_elem
->data
, 0, 0));
797 pred
= alter_predicate_for_insn (pred
, alternatives
, max_operand
,
802 /* Construct a new pattern for the new insn. */
803 insn
= copy_rtx (insn_elem
->data
);
805 pattern
= rtx_alloc (COND_EXEC
);
806 XEXP (pattern
, 0) = pred
;
807 if (XVECLEN (insn
, 1) == 1)
809 XEXP (pattern
, 1) = XVECEXP (insn
, 1, 0);
810 XVECEXP (insn
, 1, 0) = pattern
;
811 PUT_NUM_ELEM (XVEC (insn
, 1), 1);
815 XEXP (pattern
, 1) = rtx_alloc (PARALLEL
);
816 XVEC (XEXP (pattern
, 1), 0) = XVEC (insn
, 1);
817 XVEC (insn
, 1) = rtvec_alloc (1);
818 XVECEXP (insn
, 1, 0) = pattern
;
821 XSTR (insn
, 2) = alter_test_for_insn (ce_elem
, insn_elem
);
822 XTMPL (insn
, 3) = alter_output_for_insn (ce_elem
, insn_elem
,
823 alternatives
, max_operand
);
825 /* ??? Set `predicable' to false. Not crucial since it's really
826 only used here, and we won't reprocess this new pattern. */
828 /* Put the new pattern on the `other' list so that it
829 (a) is not reprocessed by other define_cond_exec patterns
830 (b) appears after all normal define_insn patterns.
832 ??? B is debatable. If one has normal insns that match
833 cond_exec patterns, they will be preferred over these
834 generated patterns. Whether this matters in practice, or if
835 it's a good thing, or whether we should thread these new
836 patterns into the define_insn chain just after their generator
837 is something we'll have to experiment with. */
839 queue_pattern (insn
, &other_tail
, insn_elem
->filename
,
844 /* If we have any DEFINE_COND_EXEC patterns, expand the DEFINE_INSN
845 patterns appropriately. */
848 process_define_cond_exec ()
850 struct queue_elem
*elem
;
852 identify_predicable_attribute ();
856 for (elem
= define_cond_exec_queue
; elem
; elem
= elem
->next
)
857 process_one_cond_exec (elem
);
865 register char *result
= xmalloc (len
+ 1);
867 memcpy (result
, s
, len
);
873 /* The entry point for initializing the reader. */
876 init_md_reader_args (argc
, argv
)
881 const char *in_fname
;
885 for (i
= 1; i
< argc
; i
++)
887 if (argv
[i
][0] != '-')
889 if (in_fname
== NULL
)
897 case 'I': /* Add directory to path for includes. */
899 struct file_name_list
*dirtmp
;
901 dirtmp
= (struct file_name_list
*)
902 xmalloc (sizeof (struct file_name_list
));
903 dirtmp
->next
= 0; /* New one goes on the end */
904 if (first_dir_md_include
== 0)
905 first_dir_md_include
= dirtmp
;
907 last_dir_md_include
->next
= dirtmp
;
908 last_dir_md_include
= dirtmp
; /* Tail follows the last one */
909 if (argv
[i
][1] == 'I' && argv
[i
][2] != 0)
910 dirtmp
->fname
= argv
[i
] + 2;
911 else if (i
+ 1 == argc
)
912 fatal ("directory name missing after -I option");
914 dirtmp
->fname
= argv
[++i
];
915 if (strlen (dirtmp
->fname
) > max_include_len
)
916 max_include_len
= strlen (dirtmp
->fname
);
920 fatal ("invalid option `%s'", argv
[i
]);
925 return init_md_reader (in_fname
);
928 /* The entry point for initializing the reader. */
931 init_md_reader (filename
)
932 const char *filename
;
939 lastsl
= strrchr (filename
, '/');
941 base_dir
= save_string (filename
, lastsl
- filename
+ 1 );
943 read_rtx_filename
= filename
;
944 input_file
= fopen (filename
, "r");
948 return FATAL_EXIT_CODE
;
951 /* Initialize the table of insn conditions. */
952 condition_table
= htab_create (n_insn_conditions
,
953 hash_c_test
, cmp_c_test
, NULL
);
955 for (i
= 0; i
< n_insn_conditions
; i
++)
956 *(htab_find_slot (condition_table
, (PTR
) &insn_conditions
[i
], INSERT
))
957 = (PTR
) &insn_conditions
[i
];
959 obstack_init (rtl_obstack
);
963 /* Read the entire file. */
969 c
= read_skip_spaces (input_file
);
973 ungetc (c
, input_file
);
974 lineno
= read_rtx_lineno
;
975 desc
= read_rtx (input_file
);
976 process_rtx (desc
, lineno
);
980 /* Process define_cond_exec patterns. */
981 if (define_cond_exec_queue
!= NULL
)
982 process_define_cond_exec ();
984 return errors
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
987 /* The entry point for reading a single rtx from an md file. */
990 read_md_rtx (lineno
, seqnr
)
994 struct queue_elem
**queue
, *elem
;
999 /* Read all patterns from a given queue before moving on to the next. */
1000 if (define_attr_queue
!= NULL
)
1001 queue
= &define_attr_queue
;
1002 else if (define_insn_queue
!= NULL
)
1003 queue
= &define_insn_queue
;
1004 else if (other_queue
!= NULL
)
1005 queue
= &other_queue
;
1010 *queue
= elem
->next
;
1012 read_rtx_filename
= elem
->filename
;
1013 *lineno
= elem
->lineno
;
1014 *seqnr
= sequence_num
;
1018 /* Discard insn patterns which we know can never match (because
1019 their C test is provably always false). If insn_elision is
1020 false, our caller needs to see all the patterns. Note that the
1021 elided patterns are never counted by the sequence numbering; it
1022 it is the caller's responsibility, when insn_elision is false, not
1023 to use elided pattern numbers for anything. */
1024 switch (GET_CODE (desc
))
1028 if (maybe_eval_c_test (XSTR (desc
, 2)) != 0)
1030 else if (insn_elision
)
1035 case DEFINE_PEEPHOLE
:
1036 case DEFINE_PEEPHOLE2
:
1037 if (maybe_eval_c_test (XSTR (desc
, 1)) != 0)
1039 else if (insn_elision
)
1050 /* Helper functions for insn elision. */
1052 /* Compute a hash function of a c_test structure, which is keyed
1053 by its ->expr field. */
1058 const struct c_test
*a
= (const struct c_test
*) x
;
1059 const unsigned char *base
, *s
= (const unsigned char *) a
->expr
;
1067 while ((c
= *s
++) != '\0')
1069 hash
+= c
+ (c
<< 17);
1074 hash
+= len
+ (len
<< 17);
1080 /* Compare two c_test expression structures. */
1086 const struct c_test
*a
= (const struct c_test
*) x
;
1087 const struct c_test
*b
= (const struct c_test
*) y
;
1089 return !strcmp (a
->expr
, b
->expr
);
1092 /* Given a string representing a C test expression, look it up in the
1093 condition_table and report whether or not its value is known
1094 at compile time. Returns a tristate: 1 for known true, 0 for
1095 known false, -1 for unknown. */
1097 maybe_eval_c_test (expr
)
1100 const struct c_test
*test
;
1101 struct c_test dummy
;
1106 if (insn_elision_unavailable
)
1110 test
= (const struct c_test
*) htab_find (condition_table
, &dummy
);
1117 /* Given a string, return the number of comma-separated elements in it.
1118 Return 0 for the null string. */
1128 for (n
= 1; *s
; s
++)
1135 /* Given a pointer to a (char *), return a pointer to the beginning of the
1136 next comma-separated element in the string. Advance the pointer given
1137 to the end of that element. Return NULL if at end of string. Caller
1138 is responsible for copying the string if necessary. White space between
1139 a comma and an element is ignored. */
1142 scan_comma_elt (pstr
)
1146 const char *p
= *pstr
;
1158 while (*p
!= ',' && *p
!= '\0')