117680Spst/* 239297Sfenner * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 317680Spst * The Regents of the University of California. All rights reserved. 417680Spst * 517680Spst * Redistribution and use in source and binary forms, with or without 617680Spst * modification, are permitted provided that: (1) source code distributions 717680Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817680Spst * distributions including binary code include the above copyright notice and 917680Spst * this paragraph in its entirety in the documentation or other materials 1017680Spst * provided with the distribution, and (3) all advertising materials mentioning 1117680Spst * features or use of this software display the following acknowledgement: 1217680Spst * ``This product includes software developed by the University of California, 1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417680Spst * the University nor the names of its contributors may be used to endorse 1517680Spst * or promote products derived from this software without specific prior 1617680Spst * written permission. 1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2017680Spst */ 2117680Spst 2217680Spst#ifndef lint 23127668Sbmsstatic const char rcsid[] _U_ = 24190207Srpaulo "@(#) $Header: /tcpdump/master/tcpdump/util.c,v 1.109 2007-01-29 09:59:42 hannes Exp $ (LBL)"; 2517680Spst#endif 2617680Spst 2756893Sfenner#ifdef HAVE_CONFIG_H 2856893Sfenner#include "config.h" 2956893Sfenner#endif 3056893Sfenner 31127668Sbms#include <tcpdump-stdinc.h> 32127668Sbms 3317680Spst#include <sys/stat.h> 3417680Spst 3517680Spst#include <errno.h> 3617680Spst#ifdef HAVE_FCNTL_H 3717680Spst#include <fcntl.h> 3817680Spst#endif 3917680Spst#include <pcap.h> 4017680Spst#include <stdio.h> 4117680Spst#include <stdarg.h> 4217680Spst#include <stdlib.h> 4317680Spst#include <string.h> 4417680Spst 4517680Spst#include "interface.h" 4617680Spst 47190207Srpaulochar * ts_format(register int, register int); 48190207Srpaulo 4917680Spst/* 50147899Ssam * Print out a null-terminated filename (or other ascii string). 5117680Spst * If ep is NULL, assume no truncation check is needed. 5217680Spst * Return true if truncated. 5317680Spst */ 5417680Spstint 5517680Spstfn_print(register const u_char *s, register const u_char *ep) 5617680Spst{ 5717680Spst register int ret; 5817680Spst register u_char c; 5917680Spst 6017680Spst ret = 1; /* assume truncated */ 6117680Spst while (ep == NULL || s < ep) { 6217680Spst c = *s++; 6317680Spst if (c == '\0') { 6417680Spst ret = 0; 6517680Spst break; 6617680Spst } 6717680Spst if (!isascii(c)) { 6817680Spst c = toascii(c); 6917680Spst putchar('M'); 7017680Spst putchar('-'); 7117680Spst } 7217680Spst if (!isprint(c)) { 7317680Spst c ^= 0x40; /* DEL to ?, others to alpha */ 7417680Spst putchar('^'); 7517680Spst } 7617680Spst putchar(c); 7717680Spst } 7817680Spst return(ret); 7917680Spst} 8017680Spst 8117680Spst/* 8217680Spst * Print out a counted filename (or other ascii string). 8317680Spst * If ep is NULL, assume no truncation check is needed. 8417680Spst * Return true if truncated. 8517680Spst */ 8617680Spstint 8717680Spstfn_printn(register const u_char *s, register u_int n, 8817680Spst register const u_char *ep) 8917680Spst{ 9017680Spst register u_char c; 9117680Spst 92127668Sbms while (n > 0 && (ep == NULL || s < ep)) { 93127668Sbms n--; 9417680Spst c = *s++; 9517680Spst if (!isascii(c)) { 9617680Spst c = toascii(c); 9717680Spst putchar('M'); 9817680Spst putchar('-'); 9917680Spst } 10017680Spst if (!isprint(c)) { 10117680Spst c ^= 0x40; /* DEL to ?, others to alpha */ 10217680Spst putchar('^'); 10317680Spst } 10417680Spst putchar(c); 10517680Spst } 106127668Sbms return (n == 0) ? 0 : 1; 10717680Spst} 10817680Spst 10917680Spst/* 110147899Ssam * Print out a null-padded filename (or other ascii string). 111147899Ssam * If ep is NULL, assume no truncation check is needed. 112147899Ssam * Return true if truncated. 113147899Ssam */ 114147899Ssamint 115147899Ssamfn_printzp(register const u_char *s, register u_int n, 116147899Ssam register const u_char *ep) 117147899Ssam{ 118147899Ssam register int ret; 119147899Ssam register u_char c; 120147899Ssam 121147899Ssam ret = 1; /* assume truncated */ 122147899Ssam while (n > 0 && (ep == NULL || s < ep)) { 123147899Ssam n--; 124147899Ssam c = *s++; 125147899Ssam if (c == '\0') { 126147899Ssam ret = 0; 127147899Ssam break; 128147899Ssam } 129147899Ssam if (!isascii(c)) { 130147899Ssam c = toascii(c); 131147899Ssam putchar('M'); 132147899Ssam putchar('-'); 133147899Ssam } 134147899Ssam if (!isprint(c)) { 135147899Ssam c ^= 0x40; /* DEL to ?, others to alpha */ 136147899Ssam putchar('^'); 137147899Ssam } 138147899Ssam putchar(c); 139147899Ssam } 140147899Ssam return (n == 0) ? 0 : ret; 141147899Ssam} 142147899Ssam 143147899Ssam/* 144190207Srpaulo * Format the timestamp 145190207Srpaulo */ 146190207Srpaulochar * 147190207Srpaulots_format(register int sec, register int usec) 148190207Srpaulo{ 149190207Srpaulo static char buf[sizeof("00:00:00.000000")]; 150190207Srpaulo (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d.%06u", 151190207Srpaulo sec / 3600, (sec % 3600) / 60, sec % 60, usec); 152190207Srpaulo 153190207Srpaulo return buf; 154190207Srpaulo} 155190207Srpaulo 156190207Srpaulo/* 15717680Spst * Print the timestamp 15817680Spst */ 15917680Spstvoid 16017680Spstts_print(register const struct timeval *tvp) 16117680Spst{ 16217680Spst register int s; 16375115Sfenner struct tm *tm; 16475115Sfenner time_t Time; 16575115Sfenner static unsigned b_sec; 16675115Sfenner static unsigned b_usec; 167190207Srpaulo int d_usec; 168190207Srpaulo int d_sec; 16917680Spst 170146773Ssam switch (tflag) { 171146773Ssam 172146773Ssam case 0: /* Default */ 17317680Spst s = (tvp->tv_sec + thiszone) % 86400; 174190207Srpaulo (void)printf("%s ", ts_format(s, tvp->tv_usec)); 17575115Sfenner break; 176146773Ssam 177146773Ssam case 1: /* No time stamp */ 178146773Ssam break; 179146773Ssam 180146773Ssam case 2: /* Unix timeval style */ 18175115Sfenner (void)printf("%u.%06u ", 18275115Sfenner (unsigned)tvp->tv_sec, 18375115Sfenner (unsigned)tvp->tv_usec); 18475115Sfenner break; 185146773Ssam 186146773Ssam case 3: /* Microseconds since previous packet */ 187190207Srpaulo case 5: /* Microseconds since first packet */ 18875115Sfenner if (b_sec == 0) { 189190207Srpaulo /* init timestamp for first packet */ 190190207Srpaulo b_usec = tvp->tv_usec; 191190207Srpaulo b_sec = tvp->tv_sec; 192190207Srpaulo } 193127668Sbms 194190207Srpaulo d_usec = tvp->tv_usec - b_usec; 195190207Srpaulo d_sec = tvp->tv_sec - b_sec; 196190207Srpaulo 197190207Srpaulo while (d_usec < 0) { 198190207Srpaulo d_usec += 1000000; 199190207Srpaulo d_sec--; 200190207Srpaulo } 201190207Srpaulo 202190207Srpaulo (void)printf("%s ", ts_format(d_sec, d_usec)); 203190207Srpaulo 204190207Srpaulo if (tflag == 3) { /* set timestamp for last packet */ 205190207Srpaulo b_sec = tvp->tv_sec; 206190207Srpaulo b_usec = tvp->tv_usec; 207190207Srpaulo } 20875115Sfenner break; 209146773Ssam 210146773Ssam case 4: /* Default + Date*/ 21175115Sfenner s = (tvp->tv_sec + thiszone) % 86400; 21275115Sfenner Time = (tvp->tv_sec + thiszone) - s; 213127668Sbms tm = gmtime (&Time); 214127668Sbms if (!tm) 215127668Sbms printf("Date fail "); 216127668Sbms else 217190207Srpaulo printf("%04d-%02d-%02d %s ", 218190207Srpaulo tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, 219190207Srpaulo ts_format(s, tvp->tv_usec)); 22075115Sfenner break; 22117680Spst } 22217680Spst} 22317680Spst 22417680Spst/* 22556893Sfenner * Print a relative number of seconds (e.g. hold time, prune timer) 22656893Sfenner * in the form 5m1s. This does no truncation, so 32230861 seconds 22756893Sfenner * is represented as 1y1w1d1h1m1s. 22856893Sfenner */ 22956893Sfennervoid 23056893Sfennerrelts_print(int secs) 23156893Sfenner{ 23298524Sfenner static const char *lengths[] = {"y", "w", "d", "h", "m", "s"}; 23398524Sfenner static const int seconds[] = {31536000, 604800, 86400, 3600, 60, 1}; 23498524Sfenner const char **l = lengths; 23598524Sfenner const int *s = seconds; 23656893Sfenner 23798524Sfenner if (secs == 0) { 23875115Sfenner (void)printf("0s"); 23975115Sfenner return; 24056893Sfenner } 24198524Sfenner if (secs < 0) { 24298524Sfenner (void)printf("-"); 24398524Sfenner secs = -secs; 24498524Sfenner } 24575115Sfenner while (secs > 0) { 24675115Sfenner if (secs >= *s) { 24775115Sfenner (void)printf("%d%s", secs / *s, *l); 24875115Sfenner secs -= (secs / *s) * *s; 24975115Sfenner } 25075115Sfenner s++; 25175115Sfenner l++; 25275115Sfenner } 25356893Sfenner} 25456893Sfenner 25556893Sfenner/* 256127668Sbms * this is a generic routine for printing unknown data; 257127668Sbms * we pass on the linefeed plus indentation string to 258127668Sbms * get a proper output - returns 0 on error 259127668Sbms */ 260127668Sbms 261127668Sbmsint 262127668Sbmsprint_unknown_data(const u_char *cp,const char *ident,int len) 263127668Sbms{ 264147899Ssam if (len < 0) { 265147899Ssam printf("%sDissector error: print_unknown_data called with negative length", 266147899Ssam ident); 267147899Ssam return(0); 268147899Ssam } 269147899Ssam if (snapend - cp < len) 270147899Ssam len = snapend - cp; 271147899Ssam if (len < 0) { 272147899Ssam printf("%sDissector error: print_unknown_data called with pointer past end of packet", 273147899Ssam ident); 274147899Ssam return(0); 275147899Ssam } 276127668Sbms hex_print(ident,cp,len); 277127668Sbms return(1); /* everything is ok */ 278127668Sbms} 279127668Sbms 280127668Sbms/* 28117680Spst * Convert a token value to a string; use "fmt" if not found. 28217680Spst */ 28317680Spstconst char * 284146773Ssamtok2strbuf(register const struct tok *lp, register const char *fmt, 285146773Ssam register int v, char *buf, size_t bufsize) 28617680Spst{ 287147899Ssam if (lp != NULL) { 288147899Ssam while (lp->s != NULL) { 289147899Ssam if (lp->v == v) 290147899Ssam return (lp->s); 291147899Ssam ++lp; 292147899Ssam } 29317680Spst } 29417680Spst if (fmt == NULL) 29517680Spst fmt = "#%d"; 296146773Ssam 297146773Ssam (void)snprintf(buf, bufsize, fmt, v); 298146773Ssam return (const char *)buf; 29917680Spst} 30017680Spst 30198524Sfenner/* 302146773Ssam * Convert a token value to a string; use "fmt" if not found. 303146773Ssam */ 304146773Ssamconst char * 305146773Ssamtok2str(register const struct tok *lp, register const char *fmt, 306146773Ssam register int v) 307146773Ssam{ 308146773Ssam static char buf[4][128]; 309146773Ssam static int idx = 0; 310146773Ssam char *ret; 311146773Ssam 312146773Ssam ret = buf[idx]; 313146773Ssam idx = (idx+1) & 3; 314146773Ssam return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0])); 315146773Ssam} 316146773Ssam 317146773Ssam/* 318127668Sbms * Convert a bit token value to a string; use "fmt" if not found. 319190207Srpaulo * this is useful for parsing bitfields, the output strings are seperated 320190207Srpaulo * if the s field is positive. 321127668Sbms */ 322190207Srpaulostatic char * 323190207Srpaulobittok2str_internal(register const struct tok *lp, register const char *fmt, 324190207Srpaulo register int v, register int sep) 325127668Sbms{ 326127668Sbms static char buf[256]; /* our stringbuffer */ 327127668Sbms int buflen=0; 328127668Sbms register int rotbit; /* this is the bit we rotate through all bitpositions */ 329127668Sbms register int tokval; 330127668Sbms 331214478Srpaulo while (lp != NULL && lp->s != NULL) { 332127668Sbms tokval=lp->v; /* load our first value */ 333127668Sbms rotbit=1; 334127668Sbms while (rotbit != 0) { 335127668Sbms /* 336127668Sbms * lets AND the rotating bit with our token value 337127668Sbms * and see if we have got a match 338127668Sbms */ 339127668Sbms if (tokval == (v&rotbit)) { 340127668Sbms /* ok we have found something */ 341190207Srpaulo buflen+=snprintf(buf+buflen, sizeof(buf)-buflen, "%s%s", 342190207Srpaulo lp->s, sep ? ", " : ""); 343127668Sbms break; 344127668Sbms } 345127668Sbms rotbit=rotbit<<1; /* no match - lets shift and try again */ 346127668Sbms } 347127668Sbms lp++; 348127668Sbms } 349127668Sbms 350190207Srpaulo /* user didn't want string seperation - no need to cut off trailing seperators */ 351190207Srpaulo if (!sep) { 352190207Srpaulo return (buf); 353190207Srpaulo } 354190207Srpaulo 355127668Sbms if (buflen != 0) { /* did we find anything */ 356127668Sbms /* yep, set the the trailing zero 2 bytes before to eliminate the last comma & whitespace */ 357127668Sbms buf[buflen-2] = '\0'; 358127668Sbms return (buf); 359127668Sbms } 360127668Sbms else { 361127668Sbms /* bummer - lets print the "unknown" message as advised in the fmt string if we got one */ 362127668Sbms if (fmt == NULL) 363127668Sbms fmt = "#%d"; 364127668Sbms (void)snprintf(buf, sizeof(buf), fmt, v); 365127668Sbms return (buf); 366127668Sbms } 367127668Sbms} 368127668Sbms 369127668Sbms/* 370190207Srpaulo * Convert a bit token value to a string; use "fmt" if not found. 371190207Srpaulo * this is useful for parsing bitfields, the output strings are not seperated. 372190207Srpaulo */ 373190207Srpaulochar * 374190207Srpaulobittok2str_nosep(register const struct tok *lp, register const char *fmt, 375190207Srpaulo register int v) 376190207Srpaulo{ 377190207Srpaulo return (bittok2str_internal(lp, fmt, v, 0)); 378190207Srpaulo} 379190207Srpaulo 380190207Srpaulo/* 381190207Srpaulo * Convert a bit token value to a string; use "fmt" if not found. 382190207Srpaulo * this is useful for parsing bitfields, the output strings are comma seperated. 383190207Srpaulo */ 384190207Srpaulochar * 385190207Srpaulobittok2str(register const struct tok *lp, register const char *fmt, 386190207Srpaulo register int v) 387190207Srpaulo{ 388190207Srpaulo return (bittok2str_internal(lp, fmt, v, 1)); 389190207Srpaulo} 390190207Srpaulo 391190207Srpaulo/* 39298524Sfenner * Convert a value to a string using an array; the macro 39398524Sfenner * tok2strary() in <interface.h> is the public interface to 39498524Sfenner * this function and ensures that the second argument is 39598524Sfenner * correct for bounds-checking. 39698524Sfenner */ 39798524Sfennerconst char * 39898524Sfennertok2strary_internal(register const char **lp, int n, register const char *fmt, 39998524Sfenner register int v) 40098524Sfenner{ 40198524Sfenner static char buf[128]; 40217680Spst 40398524Sfenner if (v >= 0 && v < n && lp[v] != NULL) 40498524Sfenner return lp[v]; 40598524Sfenner if (fmt == NULL) 40698524Sfenner fmt = "#%d"; 40798524Sfenner (void)snprintf(buf, sizeof(buf), fmt, v); 40898524Sfenner return (buf); 40998524Sfenner} 41098524Sfenner 411127668Sbms/* 412127668Sbms * Convert a 32-bit netmask to prefixlen if possible 413127668Sbms * the function returns the prefix-len; if plen == -1 414127668Sbms * then conversion was not possible; 415127668Sbms */ 416127668Sbms 417127668Sbmsint 418214478Srpaulomask2plen(u_int32_t mask) 419127668Sbms{ 420127668Sbms u_int32_t bitmasks[33] = { 421127668Sbms 0x00000000, 422127668Sbms 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 423127668Sbms 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, 424127668Sbms 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 425127668Sbms 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 426127668Sbms 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 427127668Sbms 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, 428127668Sbms 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 429127668Sbms 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff 430127668Sbms }; 431127668Sbms int prefix_len = 32; 432127668Sbms 433127668Sbms /* let's see if we can transform the mask into a prefixlen */ 434127668Sbms while (prefix_len >= 0) { 435127668Sbms if (bitmasks[prefix_len] == mask) 436127668Sbms break; 437127668Sbms prefix_len--; 438127668Sbms } 439127668Sbms return (prefix_len); 440127668Sbms} 441127668Sbms 442214478Srpaulo#ifdef INET6 443214478Srpauloint 444214478Srpaulomask62plen(const u_char *mask) 445214478Srpaulo{ 446214478Srpaulo u_char bitmasks[9] = { 447214478Srpaulo 0x00, 448214478Srpaulo 0x80, 0xc0, 0xe0, 0xf0, 449214478Srpaulo 0xf8, 0xfc, 0xfe, 0xff 450214478Srpaulo }; 451214478Srpaulo int byte; 452214478Srpaulo int cidr_len = 0; 453214478Srpaulo 454214478Srpaulo for (byte = 0; byte < 16; byte++) { 455214478Srpaulo u_int bits; 456214478Srpaulo 457214478Srpaulo for (bits = 0; bits < (sizeof (bitmasks) / sizeof (bitmasks[0])); bits++) { 458214478Srpaulo if (mask[byte] == bitmasks[bits]) { 459214478Srpaulo cidr_len += bits; 460214478Srpaulo break; 461214478Srpaulo } 462214478Srpaulo } 463214478Srpaulo 464214478Srpaulo if (mask[byte] != 0xff) 465214478Srpaulo break; 466214478Srpaulo } 467214478Srpaulo return (cidr_len); 468214478Srpaulo} 469214478Srpaulo#endif /* INET6 */ 470214478Srpaulo 47117680Spst/* VARARGS */ 47275115Sfennervoid 47317680Spsterror(const char *fmt, ...) 47417680Spst{ 47517680Spst va_list ap; 47617680Spst 47717680Spst (void)fprintf(stderr, "%s: ", program_name); 47817680Spst va_start(ap, fmt); 47917680Spst (void)vfprintf(stderr, fmt, ap); 48017680Spst va_end(ap); 48117680Spst if (*fmt) { 48217680Spst fmt += strlen(fmt); 48317680Spst if (fmt[-1] != '\n') 48417680Spst (void)fputc('\n', stderr); 48517680Spst } 48617680Spst exit(1); 48717680Spst /* NOTREACHED */ 48817680Spst} 48917680Spst 49017680Spst/* VARARGS */ 49117680Spstvoid 49217680Spstwarning(const char *fmt, ...) 49317680Spst{ 49417680Spst va_list ap; 49517680Spst 49617680Spst (void)fprintf(stderr, "%s: WARNING: ", program_name); 49717680Spst va_start(ap, fmt); 49817680Spst (void)vfprintf(stderr, fmt, ap); 49917680Spst va_end(ap); 50017680Spst if (*fmt) { 50117680Spst fmt += strlen(fmt); 50217680Spst if (fmt[-1] != '\n') 50317680Spst (void)fputc('\n', stderr); 50417680Spst } 50517680Spst} 50617680Spst 50717680Spst/* 50817680Spst * Copy arg vector into a new buffer, concatenating arguments with spaces. 50917680Spst */ 51017680Spstchar * 51117680Spstcopy_argv(register char **argv) 51217680Spst{ 51317680Spst register char **p; 51417680Spst register u_int len = 0; 51517680Spst char *buf; 51617680Spst char *src, *dst; 51717680Spst 51817680Spst p = argv; 51917680Spst if (*p == 0) 52017680Spst return 0; 52117680Spst 52217680Spst while (*p) 52317680Spst len += strlen(*p++) + 1; 52417680Spst 52517680Spst buf = (char *)malloc(len); 52617680Spst if (buf == NULL) 52717680Spst error("copy_argv: malloc"); 52817680Spst 52917680Spst p = argv; 53017680Spst dst = buf; 53117680Spst while ((src = *p++) != NULL) { 53217680Spst while ((*dst++ = *src++) != '\0') 53317680Spst ; 53417680Spst dst[-1] = ' '; 53517680Spst } 53617680Spst dst[-1] = '\0'; 53717680Spst 53817680Spst return buf; 53917680Spst} 54017680Spst 541127668Sbms/* 542127668Sbms * On Windows, we need to open the file in binary mode, so that 543127668Sbms * we get all the bytes specified by the size we get from "fstat()". 544127668Sbms * On UNIX, that's not necessary. O_BINARY is defined on Windows; 545127668Sbms * we define it as 0 if it's not defined, so it does nothing. 546127668Sbms */ 547127668Sbms#ifndef O_BINARY 548127668Sbms#define O_BINARY 0 549127668Sbms#endif 550127668Sbms 55117680Spstchar * 55217680Spstread_infile(char *fname) 55317680Spst{ 554127668Sbms register int i, fd, cc; 55517680Spst register char *cp; 55617680Spst struct stat buf; 55717680Spst 558127668Sbms fd = open(fname, O_RDONLY|O_BINARY); 55917680Spst if (fd < 0) 56017680Spst error("can't open %s: %s", fname, pcap_strerror(errno)); 56117680Spst 56217680Spst if (fstat(fd, &buf) < 0) 56317680Spst error("can't stat %s: %s", fname, pcap_strerror(errno)); 56417680Spst 56517680Spst cp = malloc((u_int)buf.st_size + 1); 56698524Sfenner if (cp == NULL) 56798524Sfenner error("malloc(%d) for %s: %s", (u_int)buf.st_size + 1, 56898524Sfenner fname, pcap_strerror(errno)); 56998524Sfenner cc = read(fd, cp, (u_int)buf.st_size); 57017680Spst if (cc < 0) 57117680Spst error("read %s: %s", fname, pcap_strerror(errno)); 57217680Spst if (cc != buf.st_size) 57317680Spst error("short read %s (%d != %d)", fname, cc, (int)buf.st_size); 57417680Spst 575127668Sbms close(fd); 576127668Sbms /* replace "# comment" with spaces */ 577127668Sbms for (i = 0; i < cc; i++) { 578127668Sbms if (cp[i] == '#') 579127668Sbms while (i < cc && cp[i] != '\n') 580127668Sbms cp[i++] = ' '; 581127668Sbms } 582127668Sbms cp[cc] = '\0'; 58317680Spst return (cp); 58417680Spst} 58575115Sfenner 58675115Sfennervoid 587172683Smlaiersafeputs(const char *s, int maxlen) 58875115Sfenner{ 589190207Srpaulo int idx = 0; 590190207Srpaulo 591172683Smlaier while (*s && idx < maxlen) { 59275115Sfenner safeputchar(*s); 593172683Smlaier idx++; 59475115Sfenner s++; 59575115Sfenner } 59675115Sfenner} 59775115Sfenner 59875115Sfennervoid 59975115Sfennersafeputchar(int c) 60075115Sfenner{ 60175115Sfenner unsigned char ch; 60275115Sfenner 60375115Sfenner ch = (unsigned char)(c & 0xff); 604111726Sfenner if (ch < 0x80 && isprint(ch)) 605111726Sfenner printf("%c", ch); 60675115Sfenner else 607190207Srpaulo printf("\\0x%02x", ch); 60875115Sfenner} 609