Mercurial > illumos > onarm
comparison usr/src/cmd/mailx/aux.c @ 0:c9caec207d52 b86
Initial porting based on b86
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Tue, 02 Jun 2009 18:56:50 +0900 |
parents | |
children | 1a15d5aaf794 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c9caec207d52 |
---|---|
1 /* | |
2 * CDDL HEADER START | |
3 * | |
4 * The contents of this file are subject to the terms of the | |
5 * Common Development and Distribution License, Version 1.0 only | |
6 * (the "License"). You may not use this file except in compliance | |
7 * with the License. | |
8 * | |
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
10 * or http://www.opensolaris.org/os/licensing. | |
11 * See the License for the specific language governing permissions | |
12 * and limitations under the License. | |
13 * | |
14 * When distributing Covered Code, include this CDDL HEADER in each | |
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
16 * If applicable, add the following below this CDDL HEADER, with the | |
17 * fields enclosed by brackets "[]" replaced with your own identifying | |
18 * information: Portions Copyright [yyyy] [name of copyright owner] | |
19 * | |
20 * CDDL HEADER END | |
21 */ | |
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ | |
23 /* All Rights Reserved */ | |
24 | |
25 | |
26 /* | |
27 * Copyright 1985-2002 Sun Microsystems, Inc. All rights reserved. | |
28 * Use is subject to license terms. | |
29 */ | |
30 | |
31 /* | |
32 * University Copyright- Copyright (c) 1982, 1986, 1988 | |
33 * The Regents of the University of California | |
34 * All Rights Reserved | |
35 * | |
36 * University Acknowledgment- Portions of this document are derived from | |
37 * software developed by the University of California, Berkeley, and its | |
38 * contributors. | |
39 */ | |
40 | |
41 #pragma ident "@(#)aux.c 1.31 05/06/08 SMI" | |
42 | |
43 #include "rcv.h" | |
44 #include <locale.h> | |
45 | |
46 /* | |
47 * mailx -- a modified version of a University of California at Berkeley | |
48 * mail program | |
49 * | |
50 * Auxiliary functions. | |
51 */ | |
52 | |
53 static char *phrase(char *name, int token, int comma); | |
54 static char *ripoff(register char *buf); | |
55 | |
56 /* | |
57 * Return a pointer to a dynamic copy of the argument. | |
58 */ | |
59 | |
60 char * | |
61 savestr(char *str) | |
62 { | |
63 register char *cp, *cp2, *top; | |
64 | |
65 for (cp = str; *cp; cp++) | |
66 ; | |
67 top = (char *)salloc((unsigned)(cp-str + 1)); | |
68 if (top == NOSTR) | |
69 return(NOSTR); | |
70 for (cp = str, cp2 = top; *cp; cp++) | |
71 *cp2++ = *cp; | |
72 *cp2 = 0; | |
73 return(top); | |
74 } | |
75 | |
76 /* | |
77 * Announce a fatal error and die. | |
78 */ | |
79 | |
80 void | |
81 panic(char *str) | |
82 { | |
83 fprintf(stderr, gettext("mailx: Panic - %s\n"), str); | |
84 exit(1); | |
85 /* NOTREACHED */ | |
86 } | |
87 | |
88 /* | |
89 * Touch the named message by setting its MTOUCH flag. | |
90 * Touched messages have the effect of not being sent | |
91 * back to the system mailbox on exit. | |
92 */ | |
93 | |
94 void | |
95 touch(int mesg) | |
96 { | |
97 register struct message *mp; | |
98 | |
99 if (mesg < 1 || mesg > msgCount) | |
100 return; | |
101 mp = &message[mesg-1]; | |
102 mp->m_flag |= MTOUCH; | |
103 if ((mp->m_flag & MREAD) == 0) | |
104 mp->m_flag |= MREAD|MSTATUS; | |
105 } | |
106 | |
107 /* | |
108 * Test to see if the passed file name is a directory. | |
109 * Return true if it is. | |
110 */ | |
111 | |
112 int | |
113 isdir(char name[]) | |
114 { | |
115 struct stat sbuf; | |
116 | |
117 if (stat(name, &sbuf) < 0) | |
118 return(0); | |
119 return((sbuf.st_mode & S_IFMT) == S_IFDIR); | |
120 } | |
121 | |
122 /* | |
123 * Count the number of arguments in the given string raw list. | |
124 */ | |
125 | |
126 int | |
127 argcount(char **argv) | |
128 { | |
129 register char **ap; | |
130 | |
131 for (ap = argv; *ap != NOSTR; ap++) | |
132 ; | |
133 return(ap-argv); | |
134 } | |
135 | |
136 /* | |
137 * Return the desired header line from the passed message | |
138 * pointer (or NOSTR if the desired header field is not available). | |
139 * Read all the header lines and concatenate multiple instances of | |
140 * the requested header. | |
141 */ | |
142 | |
143 char * | |
144 hfield(char field[], struct message *mp, char *(*add)(char *, char *)) | |
145 { | |
146 register FILE *ibuf; | |
147 char linebuf[LINESIZE]; | |
148 register long lc; | |
149 char *r = NOSTR; | |
150 | |
151 ibuf = setinput(mp); | |
152 if ((lc = mp->m_lines) <= 0) | |
153 return(NOSTR); | |
154 if (readline(ibuf, linebuf) < 0) | |
155 return(NOSTR); | |
156 lc--; | |
157 while ((lc = gethfield(ibuf, linebuf, lc)) >= 0) | |
158 if (ishfield(linebuf, field)) | |
159 r = (*add)(r, hcontents(linebuf)); | |
160 return r; | |
161 } | |
162 | |
163 /* | |
164 * Return the next header field found in the given message. | |
165 * Return > 0 if something found, <= 0 elsewise. | |
166 * Must deal with \ continuations & other such fraud. | |
167 */ | |
168 | |
169 int | |
170 gethfield( | |
171 register FILE *f, | |
172 char linebuf[], | |
173 register long rem) | |
174 { | |
175 char line2[LINESIZE]; | |
176 register char *cp, *cp2; | |
177 register int c; | |
178 | |
179 for (;;) { | |
180 if (rem <= 0) | |
181 return(-1); | |
182 if (readline(f, linebuf) < 0) | |
183 return(-1); | |
184 rem--; | |
185 if (strlen(linebuf) == 0) | |
186 return(-1); | |
187 if (isspace(linebuf[0])) | |
188 continue; | |
189 if (!headerp(linebuf)) | |
190 return(-1); | |
191 | |
192 /* | |
193 * I guess we got a headline. | |
194 * Handle wraparounding | |
195 */ | |
196 | |
197 for (;;) { | |
198 if (rem <= 0) | |
199 break; | |
200 c = getc(f); | |
201 ungetc(c, f); | |
202 if (!isspace(c) || c == '\n') | |
203 break; | |
204 if (readline(f, line2) < 0) | |
205 break; | |
206 rem--; | |
207 cp2 = line2; | |
208 for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++) | |
209 ; | |
210 if (strlen(linebuf) + strlen(cp2) >= | |
211 (unsigned)LINESIZE-2) | |
212 break; | |
213 cp = &linebuf[strlen(linebuf)]; | |
214 while (cp > linebuf && | |
215 (isspace(cp[-1]) || cp[-1] == '\\')) | |
216 cp--; | |
217 *cp++ = ' '; | |
218 for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++) | |
219 ; | |
220 nstrcpy(cp, LINESIZE - (cp - linebuf), cp2); | |
221 } | |
222 if ((c = strlen(linebuf)) > 0) { | |
223 cp = &linebuf[c-1]; | |
224 while (cp > linebuf && isspace(*cp)) | |
225 cp--; | |
226 *++cp = 0; | |
227 } | |
228 return(rem); | |
229 } | |
230 /* NOTREACHED */ | |
231 } | |
232 | |
233 /* | |
234 * Check whether the passed line is a header line of | |
235 * the desired breed. | |
236 */ | |
237 | |
238 int | |
239 ishfield(char linebuf[], char field[]) | |
240 { | |
241 register char *cp; | |
242 | |
243 if ((cp = strchr(linebuf, ':')) == NOSTR) | |
244 return(0); | |
245 if (cp == linebuf) | |
246 return(0); | |
247 *cp = 0; | |
248 if (icequal(linebuf, field)) { | |
249 *cp = ':'; | |
250 return(1); | |
251 } | |
252 *cp = ':'; | |
253 return(0); | |
254 } | |
255 | |
256 /* | |
257 * Extract the non label information from the given header field | |
258 * and return it. | |
259 */ | |
260 | |
261 char * | |
262 hcontents(char hfield[]) | |
263 { | |
264 register char *cp; | |
265 | |
266 if ((cp = strchr(hfield, ':')) == NOSTR) | |
267 return(NOSTR); | |
268 cp++; | |
269 while (*cp && isspace(*cp)) | |
270 cp++; | |
271 return(cp); | |
272 } | |
273 | |
274 /* | |
275 * Compare two strings, ignoring case. | |
276 */ | |
277 | |
278 int | |
279 icequal(register char *s1, register char *s2) | |
280 { | |
281 | |
282 while (toupper(*s1++) == toupper(*s2)) | |
283 if (*s2++ == 0) | |
284 return(1); | |
285 return(0); | |
286 } | |
287 | |
288 /* | |
289 * Copy a string, lowercasing it as we go. Here dstsize is the size of | |
290 * the destination buffer dst. | |
291 */ | |
292 void | |
293 istrcpy(char *dst, int dstsize, char *src) | |
294 { | |
295 register char *cp, *cp2; | |
296 | |
297 cp2 = dst; | |
298 cp = src; | |
299 | |
300 while (--dstsize > 0 && *cp != '\0') | |
301 *cp2++ = tolower(*cp++); | |
302 *cp2 = '\0'; | |
303 } | |
304 | |
305 /* | |
306 * The following code deals with input stacking to do source | |
307 * commands. All but the current file pointer are saved on | |
308 * the stack. | |
309 */ | |
310 | |
311 static int ssp = -1; /* Top of file stack */ | |
312 static struct sstack { | |
313 FILE *s_file; /* File we were in. */ | |
314 int s_cond; /* Saved state of conditionals */ | |
315 int s_loading; /* Loading .mailrc, etc. */ | |
316 } *sstack; | |
317 | |
318 /* | |
319 * Pushdown current input file and switch to a new one. | |
320 * Set the global flag "sourcing" so that others will realize | |
321 * that they are no longer reading from a tty (in all probability). | |
322 */ | |
323 | |
324 int | |
325 source(char name[]) | |
326 { | |
327 register FILE *fi; | |
328 register char *cp; | |
329 | |
330 if ((cp = expand(name)) == NOSTR) | |
331 return(1); | |
332 if ((fi = fopen(cp, "r")) == NULL) { | |
333 printf(gettext("Unable to open %s\n"), cp); | |
334 return(1); | |
335 } | |
336 | |
337 if (!maxfiles) { | |
338 if ((maxfiles = (int)ulimit(4, 0)) < 0) | |
339 #ifndef _NFILE | |
340 # define _NFILE 20 | |
341 #endif | |
342 maxfiles = _NFILE; | |
343 sstack = (struct sstack *)calloc(maxfiles, sizeof(struct sstack)); | |
344 if (sstack == NULL) { | |
345 printf(gettext( | |
346 "Couldn't allocate memory for sourcing stack\n")); | |
347 fclose(fi); | |
348 return(1); | |
349 } | |
350 } | |
351 | |
352 sstack[++ssp].s_file = input; | |
353 sstack[ssp].s_cond = cond; | |
354 sstack[ssp].s_loading = loading; | |
355 loading = 0; | |
356 cond = CANY; | |
357 input = fi; | |
358 sourcing++; | |
359 return(0); | |
360 } | |
361 | |
362 /* | |
363 * Pop the current input back to the previous level. | |
364 * Update the "sourcing" flag as appropriate. | |
365 */ | |
366 | |
367 int | |
368 unstack(void) | |
369 { | |
370 if (ssp < 0) { | |
371 printf(gettext("\"Source\" stack over-pop.\n")); | |
372 sourcing = 0; | |
373 return(1); | |
374 } | |
375 fclose(input); | |
376 if (cond != CANY) | |
377 printf(gettext("Unmatched \"if\"\n")); | |
378 cond = sstack[ssp].s_cond; | |
379 loading = sstack[ssp].s_loading; | |
380 input = sstack[ssp--].s_file; | |
381 if (ssp < 0) | |
382 sourcing = loading; | |
383 return(0); | |
384 } | |
385 | |
386 /* | |
387 * Touch the indicated file. | |
388 * This is nifty for the shell. | |
389 * If we have the utime() system call, this is better served | |
390 * by using that, since it will work for empty files. | |
391 * On non-utime systems, we must sleep a second, then read. | |
392 */ | |
393 | |
394 void | |
395 alter(char name[]) | |
396 { | |
397 int rc = utime(name, utimep); | |
398 extern int errno; | |
399 | |
400 if (rc != 0) { | |
401 fprintf(stderr, gettext("Cannot utime %s in aux:alter\n"), | |
402 name); | |
403 fprintf(stderr, gettext("Errno: %d\n"), errno); | |
404 } | |
405 } | |
406 | |
407 /* | |
408 * Examine the passed line buffer and | |
409 * return true if it is all blanks and tabs. | |
410 */ | |
411 | |
412 int | |
413 blankline(const char linebuf[]) | |
414 { | |
415 register const char *cp; | |
416 | |
417 for (cp = linebuf; *cp; cp++) | |
418 if (!any(*cp, " \t")) | |
419 return(0); | |
420 return(1); | |
421 } | |
422 | |
423 /* | |
424 * Skin an arpa net address according to the RFC 822 interpretation | |
425 * of "host-phrase." | |
426 */ | |
427 static char * | |
428 phrase(char *name, int token, int comma) | |
429 { | |
430 register char c; | |
431 register char *cp, *cp2; | |
432 char *bufend, *nbufp; | |
433 int gotlt, lastsp, didq; | |
434 char nbuf[LINESIZE]; | |
435 int nesting; | |
436 | |
437 if (name == NOSTR) | |
438 return(NOSTR); | |
439 if (strlen(name) >= (unsigned)LINESIZE) | |
440 nbufp = (char *)salloc(strlen(name)); | |
441 else | |
442 nbufp = nbuf; | |
443 gotlt = 0; | |
444 lastsp = 0; | |
445 bufend = nbufp; | |
446 for (cp = name, cp2 = bufend; (c = *cp++) != 0;) { | |
447 switch (c) { | |
448 case '(': | |
449 /* | |
450 Start of a comment, ignore it. | |
451 */ | |
452 nesting = 1; | |
453 while ((c = *cp) != 0) { | |
454 cp++; | |
455 switch(c) { | |
456 case '\\': | |
457 if (*cp == 0) goto outcm; | |
458 cp++; | |
459 break; | |
460 case '(': | |
461 nesting++; | |
462 break; | |
463 case ')': | |
464 --nesting; | |
465 break; | |
466 } | |
467 if (nesting <= 0) break; | |
468 } | |
469 outcm: | |
470 lastsp = 0; | |
471 break; | |
472 case '"': | |
473 /* | |
474 Start a quoted string. | |
475 Copy it in its entirety. | |
476 */ | |
477 didq = 0; | |
478 while ((c = *cp) != 0) { | |
479 cp++; | |
480 switch (c) { | |
481 case '\\': | |
482 if ((c = *cp) == 0) goto outqs; | |
483 cp++; | |
484 break; | |
485 case '"': | |
486 goto outqs; | |
487 } | |
488 if (gotlt == 0 || gotlt == '<') { | |
489 if (lastsp) { | |
490 lastsp = 0; | |
491 *cp2++ = ' '; | |
492 } | |
493 if (!didq) { | |
494 *cp2++ = '"'; | |
495 didq++; | |
496 } | |
497 *cp2++ = c; | |
498 } | |
499 } | |
500 outqs: | |
501 if (didq) | |
502 *cp2++ = '"'; | |
503 lastsp = 0; | |
504 break; | |
505 | |
506 case ' ': | |
507 case '\t': | |
508 case '\n': | |
509 if (token && (!comma || c == '\n')) { | |
510 done: | |
511 cp[-1] = 0; | |
512 return cp; | |
513 } | |
514 lastsp = 1; | |
515 break; | |
516 | |
517 case ',': | |
518 *cp2++ = c; | |
519 if (gotlt != '<') { | |
520 if (token) | |
521 goto done; | |
522 bufend = cp2; | |
523 gotlt = 0; | |
524 } | |
525 break; | |
526 | |
527 case '<': | |
528 cp2 = bufend; | |
529 gotlt = c; | |
530 lastsp = 0; | |
531 break; | |
532 | |
533 case '>': | |
534 if (gotlt == '<') { | |
535 gotlt = c; | |
536 break; | |
537 } | |
538 | |
539 /* FALLTHROUGH . . . */ | |
540 | |
541 default: | |
542 if (gotlt == 0 || gotlt == '<') { | |
543 if (lastsp) { | |
544 lastsp = 0; | |
545 *cp2++ = ' '; | |
546 } | |
547 *cp2++ = c; | |
548 } | |
549 break; | |
550 } | |
551 } | |
552 *cp2 = 0; | |
553 return (token ? --cp : equal(name, nbufp) ? name : | |
554 nbufp == nbuf ? savestr(nbuf) : nbufp); | |
555 } | |
556 | |
557 char * | |
558 skin(char *name) | |
559 { | |
560 return phrase(name, 0, 0); | |
561 } | |
562 | |
563 /* | |
564 * Here sz is the buffer size of word. | |
565 */ | |
566 char * | |
567 yankword(char *name, char *word, int sz, int comma) | |
568 { | |
569 char *cp; | |
570 | |
571 if (name == 0) | |
572 return 0; | |
573 while (isspace(*name)) | |
574 name++; | |
575 if (*name == 0) | |
576 return 0; | |
577 cp = phrase(name, 1, comma); | |
578 nstrcpy(word, sz, name); | |
579 return cp; | |
580 } | |
581 | |
582 int | |
583 docomma(char *s) | |
584 { | |
585 return s && strpbrk(s, "(<,"); | |
586 } | |
587 | |
588 /* | |
589 * Fetch the sender's name from the passed message. | |
590 */ | |
591 | |
592 char * | |
593 nameof(register struct message *mp) | |
594 { | |
595 char namebuf[LINESIZE]; | |
596 char linebuf[LINESIZE]; | |
597 register char *cp, *cp2; | |
598 register FILE *ibuf; | |
599 int first = 1, wint = 0; | |
600 char *tmp; | |
601 | |
602 if (value("from") && (cp = hfield("from", mp, addto)) != NOSTR) | |
603 return ripoff(cp); | |
604 ibuf = setinput(mp); | |
605 copy("", namebuf); | |
606 if (readline(ibuf, linebuf) <= 0) | |
607 return(savestr(namebuf)); | |
608 newname: | |
609 for (cp = linebuf; *cp != ' '; cp++) | |
610 ; | |
611 while (any(*cp, " \t")) | |
612 cp++; | |
613 for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") && | |
614 cp2-namebuf < LINESIZE-1; *cp2++ = *cp++) | |
615 ; | |
616 *cp2 = '\0'; | |
617 for (;;) { | |
618 if (readline(ibuf, linebuf) <= 0) | |
619 break; | |
620 if (substr(linebuf,"forwarded by ") != -1) | |
621 continue; | |
622 if (linebuf[0] == 'F') | |
623 cp = linebuf; | |
624 else if (linebuf[0] == '>') | |
625 cp = linebuf + 1; | |
626 else | |
627 break; | |
628 if (strncmp(cp, "From ", 5) != 0) | |
629 break; | |
630 if ((wint = substr(cp, "remote from ")) != -1) { | |
631 cp += wint + 12; | |
632 if (first) { | |
633 copy(cp, namebuf); | |
634 first = 0; | |
635 } else { | |
636 tmp = strrchr(namebuf, '!') + 1; | |
637 nstrcpy(tmp, | |
638 sizeof (namebuf) - (tmp - namebuf), | |
639 cp); | |
640 } | |
641 nstrcat(namebuf, sizeof (namebuf), "!"); | |
642 goto newname; | |
643 } else | |
644 break; | |
645 } | |
646 for (cp = namebuf; *cp == '!'; cp++); | |
647 while (ishost(host, cp)) | |
648 cp = strchr(cp, '!') + 1; | |
649 if (value("mustbang") && !strchr(cp, '!')) { | |
650 snprintf(linebuf, sizeof (linebuf), "%s!%s", | |
651 host, cp); | |
652 cp = linebuf; | |
653 } | |
654 if (cp2 = hfield("from", mp, addto)) | |
655 return(splice(cp, cp2)); | |
656 else | |
657 return(savestr(cp)); | |
658 } | |
659 | |
660 /* | |
661 * Splice an address into a commented recipient header. | |
662 */ | |
663 char * | |
664 splice(char *addr, char *hdr) | |
665 { | |
666 char buf[LINESIZE]; | |
667 char *cp, *cp2; | |
668 | |
669 if (cp = strchr(hdr, '<')) { | |
670 cp2 = strchr(cp, '>'); | |
671 if (cp2 == NULL) { | |
672 nstrcpy(buf, sizeof (buf), addr); | |
673 } else { | |
674 snprintf(buf, sizeof (buf), "%.*s%s%s", | |
675 cp - hdr + 1, hdr, addr, cp2); | |
676 } | |
677 } else if (cp = strchr(hdr, '(')) { | |
678 snprintf(buf, sizeof (buf), "%s %s", | |
679 addr, cp); | |
680 } else | |
681 nstrcpy(buf, sizeof (buf), addr); | |
682 return savestr(ripoff(buf)); | |
683 } | |
684 | |
685 static char * | |
686 ripoff(register char *buf) | |
687 { | |
688 register char *cp; | |
689 | |
690 cp = buf + strlen(buf); | |
691 while (--cp >= buf && isspace(*cp)); | |
692 if (cp >= buf && *cp == ',') | |
693 cp--; | |
694 *++cp = 0; | |
695 return buf; | |
696 } | |
697 | |
698 /* | |
699 * Are any of the characters in the two strings the same? | |
700 */ | |
701 | |
702 int | |
703 anyof(register char *s1, register char *s2) | |
704 { | |
705 register int c; | |
706 | |
707 while ((c = *s1++) != 0) | |
708 if (any(c, s2)) | |
709 return(1); | |
710 return(0); | |
711 } | |
712 | |
713 /* | |
714 * See if the given header field is supposed to be ignored. | |
715 * Fields of the form "Content-*" can't be ignored when saving. | |
716 */ | |
717 int | |
718 isign(char *field, int saving) | |
719 { | |
720 char realfld[BUFSIZ]; | |
721 | |
722 /* | |
723 * Lower-case the string, so that "Status" and "status" | |
724 * will hash to the same place. | |
725 */ | |
726 istrcpy(realfld, sizeof (realfld), field); | |
727 | |
728 if (saving && strncmp(realfld, "content-", 8) == 0) | |
729 return (0); | |
730 | |
731 if (nretained > 0) | |
732 return (!member(realfld, retain)); | |
733 else | |
734 return (member(realfld, ignore)); | |
735 } | |
736 | |
737 int | |
738 member(register char *realfield, register struct ignore **table) | |
739 { | |
740 register struct ignore *igp; | |
741 | |
742 for (igp = table[hash(realfield)]; igp != 0; igp = igp->i_link) | |
743 if (equal(igp->i_field, realfield)) | |
744 return (1); | |
745 | |
746 return (0); | |
747 } | |
748 | |
749 /* | |
750 * This routine looks for string2 in string1. | |
751 * If found, it returns the position string2 is found at, | |
752 * otherwise it returns a -1. | |
753 */ | |
754 int | |
755 substr(char *string1, char *string2) | |
756 { | |
757 int i, j, len1, len2; | |
758 | |
759 len1 = strlen(string1); | |
760 len2 = strlen(string2); | |
761 for (i = 0; i < len1 - len2 + 1; i++) { | |
762 for (j = 0; j < len2 && string1[i+j] == string2[j]; j++) | |
763 ; | |
764 if (j == len2) | |
765 return(i); | |
766 } | |
767 return(-1); | |
768 } | |
769 | |
770 /* | |
771 * Copies src to the dstsize buffer at dst. The copy will never | |
772 * overflow the destination buffer and the buffer will always be null | |
773 * terminated. | |
774 */ | |
775 char * | |
776 nstrcpy(char *dst, int dstsize, char *src) | |
777 { | |
778 char *cp, *cp2; | |
779 | |
780 cp2 = dst; | |
781 cp = src; | |
782 | |
783 while (--dstsize > 0 && *cp != '\0') | |
784 *cp2++ = *cp++; | |
785 *cp2 = '\0'; | |
786 return(dst); | |
787 } | |
788 | |
789 /* | |
790 * Appends src to the dstsize buffer at dst. The append will never | |
791 * overflow the destination buffer and the buffer will always be null | |
792 * terminated. | |
793 */ | |
794 char * | |
795 nstrcat(char *dst, int dstsize, char *src) | |
796 { | |
797 char *cp, *cp2; | |
798 | |
799 cp2 = dst; | |
800 cp = src; | |
801 | |
802 while (*cp2 != '\0') { | |
803 cp2++; | |
804 dstsize--; | |
805 } | |
806 while (--dstsize > 0 && *cp != '\0') | |
807 *cp2++ = *cp++; | |
808 *cp2 = '\0'; | |
809 return(dst); | |
810 } |