xref: /openbsd-src/usr.bin/rpcgen/rpc_cout.c (revision 5054e3e78af0749a9bb00ba9a024b3ee2d90290f)
1 /*	$OpenBSD: rpc_cout.c,v 1.20 2009/10/27 23:59:42 deraadt Exp $	*/
2 /*	$NetBSD: rpc_cout.c,v 1.6 1996/10/01 04:13:53 cgd Exp $	*/
3 /*
4  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5  * unrestricted use provided that this legend is included on all tape
6  * media and as a part of the software program in whole or part.  Users
7  * may copy or modify Sun RPC without charge, but are not authorized
8  * to license or distribute it to anyone else except as part of a product or
9  * program developed by the user or with the express written consent of
10  * Sun Microsystems, Inc.
11  *
12  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
13  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
14  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
15  *
16  * Sun RPC is provided with no support and without any obligation on the
17  * part of Sun Microsystems, Inc. to assist in its use, correction,
18  * modification or enhancement.
19  *
20  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
21  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
22  * OR ANY PART THEREOF.
23  *
24  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
25  * or profits or other special, indirect and consequential damages, even if
26  * Sun has been advised of the possibility of such damages.
27  *
28  * Sun Microsystems, Inc.
29  * 2550 Garcia Avenue
30  * Mountain View, California  94043
31  */
32 
33 /*
34  * rpc_cout.c, XDR routine outputter for the RPC protocol compiler
35  */
36 #include <sys/cdefs.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include "rpc_parse.h"
42 #include "rpc_util.h"
43 
44 static int findtype(definition *, char *);
45 static int undefined(char *);
46 static void print_generic_header(char *, int);
47 static void print_header(definition *);
48 static void print_prog_header(proc_list *);
49 static void print_trailer(void);
50 static void print_ifopen(int, char *);
51 static void print_ifarg(char *);
52 static void print_ifsizeof(char *, char *);
53 static void print_ifclose(int);
54 static void print_ifstat(int, char *, char *, relation, char *, char *, char *);
55 static void emit_program(definition *);
56 static void emit_enum(definition *);
57 static void emit_union(definition *);
58 static void emit_struct(definition *);
59 static void emit_typedef(definition *);
60 static void print_stat(int, declaration *);
61 void emit_inline(declaration *, int);
62 void emit_single_in_line(declaration *, int, relation);
63 
64 /*
65  * Emit the C-routine for the given definition
66  */
67 void
68 emit(def)
69 	definition *def;
70 {
71 	if (def->def_kind == DEF_CONST) {
72 		return;
73 	}
74 	if (def->def_kind == DEF_PROGRAM) {
75 		emit_program(def);
76 		return;
77 	}
78 	if (def->def_kind == DEF_TYPEDEF) {
79 		/* now we need to handle declarations like struct typedef foo
80 		 * foo; since we dont want this to be expanded into 2 calls to
81 		 * xdr_foo */
82 
83 		if (strcmp(def->def.ty.old_type, def->def_name) == 0)
84 			return;
85 	}
86 
87 	print_header(def);
88 	switch (def->def_kind) {
89 	case DEF_UNION:
90 		emit_union(def);
91 		break;
92 	case DEF_ENUM:
93 		emit_enum(def);
94 		break;
95 	case DEF_STRUCT:
96 		emit_struct(def);
97 		break;
98 	case DEF_TYPEDEF:
99 		emit_typedef(def);
100 		break;
101 	}
102 	print_trailer();
103 }
104 
105 static int
106 findtype(def, type)
107 	definition *def;
108 	char	*type;
109 {
110 
111 	if (def->def_kind == DEF_PROGRAM || def->def_kind == DEF_CONST) {
112 		return (0);
113 	} else {
114 		return (streq(def->def_name, type));
115 	}
116 }
117 
118 static int
119 undefined(type)
120 	char	*type;
121 {
122 	definition *def;
123 
124 	def = (definition *) FINDVAL(defined, type, findtype);
125 	return (def == NULL);
126 }
127 
128 static void
129 print_generic_header(procname, pointerp)
130 	char	*procname;
131 	int	pointerp;
132 {
133 	fprintf(fout, "\n");
134 	fprintf(fout, "bool_t\n");
135 	if (Cflag) {
136 		fprintf(fout, "xdr_%s(", procname);
137 		fprintf(fout, "XDR *xdrs, ");
138 		fprintf(fout, "%s ", procname);
139 		if (pointerp)
140 			fprintf(fout, "*");
141 		fprintf(fout, "objp)\n{\n");
142 	} else {
143 		fprintf(fout, "xdr_%s(xdrs, objp)\n", procname);
144 		fprintf(fout, "\tXDR *xdrs;\n");
145 		fprintf(fout, "\t%s ", procname);
146 		if (pointerp)
147 			fprintf(fout, "*");
148 		fprintf(fout, "objp;\n{\n");
149 	}
150 }
151 
152 static void
153 print_header(def)
154 	definition *def;
155 {
156 	print_generic_header(def->def_name,
157 	    def->def_kind != DEF_TYPEDEF ||
158 	    !isvectordef(def->def.ty.old_type, def->def.ty.rel));
159 
160 	/* Now add Inline support */
161 
162 	if (doinline == 0)
163 		return;
164 }
165 
166 static void
167 print_prog_header(plist)
168 	proc_list *plist;
169 {
170 	print_generic_header(plist->args.argname, 1);
171 }
172 
173 static void
174 print_trailer()
175 {
176 	fprintf(fout, "\treturn (TRUE);\n");
177 	fprintf(fout, "}\n");
178 }
179 
180 static void
181 print_ifopen(indent, name)
182 	int     indent;
183 	char   *name;
184 {
185 	tabify(fout, indent);
186 	fprintf(fout, "if (!xdr_%s(xdrs", name);
187 }
188 
189 static void
190 print_ifarg(arg)
191 	char   *arg;
192 {
193 	fprintf(fout, ", %s", arg);
194 }
195 
196 static void
197 print_ifsizeof(prefix, type)
198 	char   *prefix;
199 	char   *type;
200 {
201 	if (streq(type, "bool")) {
202 		fprintf(fout, ", sizeof(bool_t), (xdrproc_t)xdr_bool");
203 	} else {
204 		fprintf(fout, ", sizeof(");
205 		if (undefined(type) && prefix) {
206 			fprintf(fout, "%s ", prefix);
207 		}
208 		fprintf(fout, "%s), (xdrproc_t)xdr_%s", type, type);
209 	}
210 }
211 
212 static void
213 print_ifclose(indent)
214 	int     indent;
215 {
216 	fprintf(fout, "))\n");
217 	tabify(fout, indent);
218 	fprintf(fout, "\treturn (FALSE);\n");
219 }
220 
221 static void
222 print_ifstat(indent, prefix, type, rel, amax, objname, name)
223 	int     indent;
224 	char   *prefix;
225 	char   *type;
226 	relation rel;
227 	char   *amax;
228 	char   *objname;
229 	char   *name;
230 {
231 	char   *alt = NULL;
232 
233 	switch (rel) {
234 	case REL_POINTER:
235 		print_ifopen(indent, "pointer");
236 		print_ifarg("(char **)");
237 		fprintf(fout, "%s", objname);
238 		print_ifsizeof(prefix, type);
239 		break;
240 	case REL_VECTOR:
241 		if (streq(type, "string")) {
242 			alt = "string";
243 		} else
244 			if (streq(type, "opaque")) {
245 				alt = "opaque";
246 			}
247 		if (alt) {
248 			print_ifopen(indent, alt);
249 			print_ifarg(objname);
250 			print_ifarg(amax);
251 		} else {
252 			print_ifopen(indent, "vector");
253 			print_ifarg("(char *)");
254 			fprintf(fout, "%s,\n", objname);
255 			tabify(fout, indent);
256 			fprintf(fout, "    %s", amax);
257 		}
258 		if (!alt) {
259 			print_ifsizeof(prefix, type);
260 		}
261 		break;
262 	case REL_ARRAY:
263 		if (streq(type, "string")) {
264 			alt = "string";
265 		} else
266 			if (streq(type, "opaque")) {
267 				alt = "bytes";
268 			}
269 		if (streq(type, "string")) {
270 			print_ifopen(indent, alt);
271 			print_ifarg(objname);
272 			print_ifarg(amax);
273 		} else {
274 			if (alt) {
275 				print_ifopen(indent, alt);
276 			} else {
277 				print_ifopen(indent, "array");
278 			}
279 			print_ifarg("(char **)");
280 			if (*objname == '&') {
281 				fprintf(fout, "%s.%s_val,\n\t    (u_int *)%s.%s_len",
282 				    objname, name, objname, name);
283 			} else {
284 				fprintf(fout, "&%s->%s_val,\n\t    (u_int *)&%s->%s_len",
285 				    objname, name, objname, name);
286 			}
287 			fprintf(fout, ",\n\t    %s", amax);
288 		}
289 		if (!alt) {
290 			print_ifsizeof(prefix, type);
291 		}
292 		break;
293 	case REL_ALIAS:
294 		print_ifopen(indent, type);
295 		print_ifarg(objname);
296 		break;
297 	}
298 	print_ifclose(indent);
299 }
300 
301 /* ARGSUSED */
302 static void
303 emit_enum(def)
304 	definition *def;
305 {
306 	fprintf(fout, "\n");
307 
308 	print_ifopen(1, "enum");
309 	print_ifarg("(enum_t *)objp");
310 	print_ifclose(1);
311 }
312 
313 static void
314 emit_program(def)
315 	definition *def;
316 {
317 	decl_list *dl;
318 	version_list *vlist;
319 	proc_list *plist;
320 
321 	for (vlist = def->def.pr.versions; vlist != NULL; vlist = vlist->next)
322 		for (plist = vlist->procs; plist != NULL; plist = plist->next) {
323 			if (!newstyle || plist->arg_num < 2)
324 				continue;	/* old style, or single
325 						 * argument */
326 			print_prog_header(plist);
327 			for (dl = plist->args.decls; dl != NULL;
328 			    dl = dl->next)
329 				print_stat(1, &dl->decl);
330 			print_trailer();
331 		}
332 }
333 
334 static void
335 emit_union(def)
336 	definition *def;
337 {
338 	declaration *dflt;
339 	case_list *cl;
340 	declaration *cs;
341 	char   *object;
342 	char   *vecformat = "objp->%s_u.%s";
343 	char   *format = "&objp->%s_u.%s";
344 
345 	fprintf(fout, "\n");
346 	print_stat(1, &def->def.un.enum_decl);
347 	fprintf(fout, "\tswitch (objp->%s) {\n", def->def.un.enum_decl.name);
348 	for (cl = def->def.un.cases; cl != NULL; cl = cl->next) {
349 		fprintf(fout, "\tcase %s:\n", cl->case_name);
350 		if (cl->contflag == 1)	/* a continued case statement */
351 			continue;
352 		cs = &cl->case_decl;
353 		if (!streq(cs->type, "void")) {
354 			int len = strlen(def->def_name) + strlen(format) +
355 			    strlen(cs->name) + 1;
356 
357 			object = alloc(len);
358 			if (object == NULL) {
359 				fprintf(stderr, "Fatal error: no memory\n");
360 				crash();
361 			}
362 			if (isvectordef(cs->type, cs->rel)) {
363 				snprintf(object, len, vecformat, def->def_name,
364 				    cs->name);
365 			} else {
366 				snprintf(object, len, format, def->def_name,
367 				    cs->name);
368 			}
369 			print_ifstat(2, cs->prefix, cs->type, cs->rel, cs->array_max,
370 			    object, cs->name);
371 			free(object);
372 		}
373 		fprintf(fout, "\t\tbreak;\n");
374 	}
375 	dflt = def->def.un.default_decl;
376 	if (dflt != NULL) {
377 		if (!streq(dflt->type, "void")) {
378 			int len = strlen(def->def_name) + strlen(format) +
379 			    strlen(dflt->name) + 1;
380 
381 			fprintf(fout, "\tdefault:\n");
382 			object = alloc(len);
383 			if (object == NULL) {
384 				fprintf(stderr, "Fatal error: no memory\n");
385 				crash();
386 			}
387 			if (isvectordef(dflt->type, dflt->rel)) {
388 				snprintf(object, len, vecformat, def->def_name,
389 				    dflt->name);
390 			} else {
391 				snprintf(object, len, format, def->def_name,
392 				    dflt->name);
393 			}
394 
395 			print_ifstat(2, dflt->prefix, dflt->type, dflt->rel,
396 			    dflt->array_max, object, dflt->name);
397 			free(object);
398 			fprintf(fout, "\t\tbreak;\n");
399 		}
400 	} else {
401 		fprintf(fout, "\tdefault:\n");
402 		fprintf(fout, "\t\treturn (FALSE);\n");
403 	}
404 
405 	fprintf(fout, "\t}\n");
406 }
407 
408 static void
409 emit_struct(def)
410 	definition *def;
411 {
412 	decl_list *dl;
413 	int     i, j, size, flag;
414 	decl_list *cur, *psav;
415 	bas_type *ptr;
416 	char   *sizestr, *plus;
417 	char    ptemp[256];
418 	int     can_inline;
419 
420 	if (doinline == 0) {
421 		for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
422 			print_stat(1, &dl->decl);
423 		return;
424 	}
425 	for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
426 		if (dl->decl.rel == REL_VECTOR) {
427 			fprintf(fout, "\tint i;\n");
428 			break;
429 		}
430 	fprintf(fout, "\n");
431 
432 	size = 0;
433 	can_inline = 0;
434 	for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
435 		if (dl->decl.prefix == NULL &&
436 		    (ptr = find_type(dl->decl.type)) != NULL &&
437 		    (dl->decl.rel == REL_ALIAS || dl->decl.rel == REL_VECTOR)) {
438 			if (dl->decl.rel == REL_ALIAS)
439 				size += ptr->length;
440 			else {
441 				can_inline = 1;
442 				break;	/* can be inlined */
443 			}
444 		} else {
445 			if (size >= doinline) {
446 				can_inline = 1;
447 				break;	/* can be inlined */
448 			}
449 			size = 0;
450 		}
451 	if (size > doinline)
452 		can_inline = 1;
453 
454 	if (can_inline == 0) {	/* can not inline, drop back to old mode */
455 		fprintf(fout, "\n");
456 		for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
457 			print_stat(1, &dl->decl);
458 		return;
459 	}
460 
461 	/* May cause lint to complain. but  ... */
462 	fprintf(fout, "\tint32_t *buf;\n");
463 
464 	flag = PUT;
465 	for (j = 0; j < 2; j++) {
466 		if (flag == PUT)
467 			fprintf(fout, "\n\tif (xdrs->x_op == XDR_ENCODE) {\n");
468 		else
469 			fprintf(fout, "\t\treturn (TRUE);\n\t} else if (xdrs->x_op == XDR_DECODE) {\n");
470 
471 		i = 0;
472 		size = 0;
473 		sizestr = NULL;
474 		for (dl = def->def.st.decls; dl != NULL; dl = dl->next) {	/* xxx */
475 
476 			/* now walk down the list and check for basic types */
477 			if (dl->decl.prefix == NULL &&
478 			    (ptr = find_type(dl->decl.type)) != NULL &&
479 			    (dl->decl.rel == REL_ALIAS || dl->decl.rel == REL_VECTOR)) {
480 				if (i == 0)
481 					cur = dl;
482 				i++;
483 
484 				if (dl->decl.rel == REL_ALIAS)
485 					size += ptr->length;
486 				else {
487 					/* this is required to handle arrays */
488 
489 					if (sizestr == NULL)
490 						plus = "";
491 					else
492 						plus = "+";
493 
494 					if (ptr->length != 1)
495 						snprintf(ptemp, sizeof ptemp,
496 						    "%s%s* %d", plus,
497 						    dl->decl.array_max,
498 						    ptr->length);
499 					else
500 						snprintf(ptemp, sizeof ptemp,
501 						    "%s%s", plus,
502 						    dl->decl.array_max);
503 
504 					/* now concatenate to sizestr !!!! */
505 					if (sizestr == NULL) {
506 						sizestr = strdup(ptemp);
507 						if (sizestr == NULL) {
508 							fprintf(stderr,
509 							    "Fatal error: no memory\n");
510 							crash();
511 						}
512 					} else {
513 						size_t len;
514 
515 						len = strlen(sizestr) +
516 						    strlen(ptemp) + 1;
517 						sizestr = (char *)realloc(sizestr, len);
518 						if (sizestr == NULL) {
519 							fprintf(stderr,
520 							    "Fatal error: no memory\n");
521 							crash();
522 						}
523 						/* build up length of array */
524 						strlcat(sizestr, ptemp, len);
525 					}
526 				}
527 
528 			} else {
529 				if (i > 0) {
530 					if (sizestr == NULL && size < doinline) {
531 						/* don't expand into inline
532 						 * code if size < doinline */
533 						while (cur != dl) {
534 							print_stat(2, &cur->decl);
535 							cur = cur->next;
536 						}
537 					} else {
538 						/* were already looking at a
539 						 * xdr_inlineable structure */
540 						if (sizestr == NULL)
541 							fprintf(fout,
542 							    "\t\tbuf = (int32_t *)XDR_INLINE(xdrs,\n\t\t    %d * BYTES_PER_XDR_UNIT);", size);
543 						else if (size == 0)
544 							fprintf(fout,
545 							    "\t\tbuf = (int32_t *)XDR_INLINE(xdrs,\n\t\t    %s * BYTES_PER_XDR_UNIT);",
546 								    sizestr);
547 						else
548 							fprintf(fout,
549 							    "\t\tbuf = (int32_t *)XDR_INLINE(xdrs,\n\t\t    (%d + %s) * BYTES_PER_XDR_UNIT);", size, sizestr);
550 
551 						fprintf(fout,
552 						    "\n\t\tif (buf == NULL) {\n");
553 
554 						psav = cur;
555 						while (cur != dl) {
556 							print_stat(3, &cur->decl);
557 							cur = cur->next;
558 						}
559 
560 						fprintf(fout, "\t\t} else {\n");
561 
562 						cur = psav;
563 						while (cur != dl) {
564 							emit_inline(&cur->decl, flag);
565 							cur = cur->next;
566 						}
567 						fprintf(fout, "\t\t}\n");
568 					}
569 				}
570 				size = 0;
571 				i = 0;
572 				sizestr = NULL;
573 				print_stat(2, &dl->decl);
574 			}
575 		}
576 		if (i > 0) {
577 			if (sizestr == NULL && size < doinline) {
578 				/* don't expand into inline code if size <
579 				 * doinline */
580 				while (cur != dl) {
581 					print_stat(2, &cur->decl);
582 					cur = cur->next;
583 				}
584 			} else {
585 				/* were already looking at a xdr_inlineable
586 				 * structure */
587 				if (sizestr == NULL)
588 					fprintf(fout, "\t\tbuf = (int32_t *)XDR_INLINE(xdrs,\n\t\t    %d * BYTES_PER_XDR_UNIT);",
589 					    size);
590 				else
591 					if (size == 0)
592 						fprintf(fout,
593 						    "\t\tbuf = (int32_t *)XDR_INLINE(xdrs,\n\t\t    %s * BYTES_PER_XDR_UNIT);",
594 						    sizestr);
595 					else
596 						fprintf(fout,
597 						    "\t\tbuf = (int32_t *)XDR_INLINE(xdrs,\n\t\t    (%d + %s) * BYTES_PER_XDR_UNIT);",
598 						    size, sizestr);
599 
600 				fprintf(fout, "\n\t\tif (buf == NULL) {\n");
601 
602 				psav = cur;
603 				while (cur != NULL) {
604 					print_stat(3, &cur->decl);
605 					cur = cur->next;
606 				}
607 				fprintf(fout, "\t\t} else {\n");
608 
609 				cur = psav;
610 				while (cur != dl) {
611 					emit_inline(&cur->decl, flag);
612 					cur = cur->next;
613 				}
614 
615 				fprintf(fout, "\t\t}\n");
616 
617 			}
618 		}
619 		flag = GET;
620 	}
621 	fprintf(fout, "\t\treturn (TRUE);\n\t}\n\n");
622 
623 	/* now take care of XDR_FREE case */
624 
625 	for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
626 		print_stat(1, &dl->decl);
627 }
628 
629 static void
630 emit_typedef(def)
631 	definition *def;
632 {
633 	char   *prefix = def->def.ty.old_prefix;
634 	char   *type = def->def.ty.old_type;
635 	char   *amax = def->def.ty.array_max;
636 	relation rel = def->def.ty.rel;
637 
638 	fprintf(fout, "\n");
639 	print_ifstat(1, prefix, type, rel, amax, "objp", def->def_name);
640 }
641 
642 static void
643 print_stat(indent, dec)
644 	declaration *dec;
645 	int     indent;
646 {
647 	char   *prefix = dec->prefix;
648 	char   *type = dec->type;
649 	char   *amax = dec->array_max;
650 	relation rel = dec->rel;
651 	char    name[256];
652 
653 	if (isvectordef(type, rel)) {
654 		snprintf(name, sizeof name, "objp->%s", dec->name);
655 	} else {
656 		snprintf(name, sizeof name, "&objp->%s", dec->name);
657 	}
658 	print_ifstat(indent, prefix, type, rel, amax, name, dec->name);
659 }
660 
661 char   *upcase(char *);
662 
663 void
664 emit_inline(decl, flag)
665 	declaration *decl;
666 	int     flag;
667 {
668 	/*check whether an array or not */
669 
670 	switch (decl->rel) {
671 	case REL_ALIAS:
672 		fprintf(fout, "\t");
673 		emit_single_in_line(decl, flag, REL_ALIAS);
674 		break;
675 	case REL_VECTOR:
676 		fprintf(fout, "\t\t\t{\n\t\t\t\t%s *genp;\n\n", decl->type);
677 		fprintf(fout, "\t\t\t\tfor (i = 0, genp = objp->%s;\n\t\t\t\t    i < %s; i++) {\n\t\t\t",
678 		    decl->name, decl->array_max);
679 		emit_single_in_line(decl, flag, REL_VECTOR);
680 		fprintf(fout, "\t\t\t\t}\n\t\t\t}\n");
681 
682 	}
683 }
684 
685 void
686 emit_single_in_line(decl, flag, rel)
687 	declaration *decl;
688 	int     flag;
689 	relation rel;
690 {
691 	char   *upp_case;
692 	int     freed = 0;
693 
694 	if (flag == PUT)
695 		fprintf(fout, "\t\tIXDR_PUT_");
696 	else
697 		if (rel == REL_ALIAS)
698 			fprintf(fout, "\t\tobjp->%s = IXDR_GET_", decl->name);
699 		else
700 			fprintf(fout, "\t\t*genp++ = IXDR_GET_");
701 
702 	upp_case = upcase(decl->type);
703 
704 	/* hack  - XX */
705 	if (strcmp(upp_case, "INT") == 0) {
706 		free(upp_case);
707 		freed = 1;
708 		upp_case = "LONG";
709 	}
710 	if (strcmp(upp_case, "U_INT") == 0) {
711 		free(upp_case);
712 		freed = 1;
713 		upp_case = "U_LONG";
714 	}
715 	if (flag == PUT)
716 		if (rel == REL_ALIAS)
717 			fprintf(fout, "%s(buf, objp->%s);\n", upp_case, decl->name);
718 		else
719 			fprintf(fout, "%s(buf, *genp++);\n", upp_case);
720 
721 	else
722 		fprintf(fout, "%s(buf);\n", upp_case);
723 	if (!freed)
724 		free(upp_case);
725 }
726 
727 char *
728 upcase(str)
729 	char   *str;
730 {
731 	char   *ptr, *hptr;
732 
733 	ptr = (char *) malloc(strlen(str)+1);
734 	if (ptr == (char *) NULL) {
735 		fprintf(stderr, "malloc failed\n");
736 		exit(1);
737 	}
738 
739 	hptr = ptr;
740 	while (*str != '\0')
741 		*ptr++ = toupper(*str++);
742 
743 	*ptr = '\0';
744 	return (hptr);
745 }
746