conv.c

来自「一个很有名的浏览器」· C语言 代码 · 共 476 行

C
476
字号
/* Conversion functions *//* $Id: conv.c,v 1.70 2004/11/25 23:50:15 miciah Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <ctype.h>#include <errno.h>#ifdef HAVE_LIMITS_H#include <limits.h>#endif#include <stdlib.h>#include <string.h>#include "elinks.h"#include "intl/charsets.h" /* NBSP_CHAR */#include "util/conv.h"#include "util/error.h"#include "util/string.h"#include "util/ttime.h"/* This function takes string @s and stores the @number (of a result width * @width) in string format there, starting at position [*@slen]. If the number * would take more space than @width, it is truncated and only the _last_ * digits of it are inserted to the string. If the number takes less space than * @width, it is padded by @fillchar from left. * @base defined which base should be used (10, 16, 8, 2, ...) * @upper selects either hexa uppercased chars or lowercased chars. * * A NUL char is always added at the end of the string. @s must point to a * sufficiently large memory space, at least *@slen + @width + 1. * * Examples: * * elinks_ulongcat(s, NULL, 12345, 4, 0, 10, 0) : s = "2345" * elinks_ulongcat(s, NULL, 255, 4, '*', 16, 1) : s = "**FF" * elinks_ulongcat(s, NULL, 123, 5, '0', 10, 0) : s = "00123" * * Note that this function exists to provide a fast and efficient, however * still quite powerful alternative to sprintf(). It is optimized for speed and * is *MUCH* faster than sprintf(). If you can use it, use it ;-). But do not * get too enthusiastic, do not use it in cases where it would break i18n. *//* The function returns 0 if OK or width needed for the whole number to fit * there, if it had to be truncated. A negative value signs an error. */int inlineelinks_ulongcat(unsigned char *s, unsigned int *slen,		unsigned long number, unsigned int width,		unsigned char fillchar, unsigned int base,		unsigned int upper){	static unsigned char unum[]= "0123456789ABCDEF";	static unsigned char lnum[]= "0123456789abcdef";	unsigned char *to_num = (unsigned char *) (upper ? &unum : &lnum);	unsigned int start = slen ? *slen : 0;	unsigned int nlen = 1; /* '0' is one char, we can't have less. */	unsigned int pos = start; /* starting position of the number */	unsigned long q = number;	int ret = 0;	if (width < 1 || !s || base < 2 || base > 16) return -1;	/* Count the length of the number in chars. */	while (q > (base - 1)) {		nlen++;		q /= base;	}	/* If max. width attained, truncate. */	if (nlen > width) {		ret = nlen;		nlen = width;	}	if (slen) *slen += nlen;	/* Fill left space with fillchar. */	if (fillchar) {		/* ie. width = 4 nlen = 2 -> pad = 2 */		unsigned int pad = width - nlen;		if (pad > 0) {			/* Relocate the start of number. */			if (slen) *slen += pad;			pos += pad;			/* Pad. */			while (pad > 0) s[--pad + start] = fillchar;		}	}	s[pos + nlen] = '\0';	/* Now write number starting from end. */	while (nlen > 0) {		s[--nlen + pos] = to_num[(number % base)];		number /= base;	}	return ret;}/* Similar to elinks_ulongcat() but for long number. */int inlineelinks_longcat(unsigned char *s, unsigned int *slen,	       long number, unsigned int width,	       unsigned char fillchar, unsigned int base,	       unsigned int upper){	unsigned char *p = s;	if (number < 0 && width > 0) {		if (slen) p[(*slen)++] = '-';		else *(p++) = '-';		number = -number;		width--;	}	return elinks_ulongcat(p, slen, number, width, fillchar, base, upper);}struct string *add_long_to_string(struct string *string, long number){	unsigned char buffer[32];	int length = 0;	int width;	assert(string);	if_assert_failed { return NULL; }	width = longcat(buffer, &length, number, sizeof(buffer) - 1, 0);	if (width < 0 || !length) return NULL;	return add_bytes_to_string(string, buffer, length);}struct string *add_knum_to_string(struct string *string, long num){	int ret;	unsigned char t[32];	int tlen = 0;	if (num && (num / (1024 * 1024)) * (1024 * 1024) == num) {		ret = longcat(&t, &tlen, num / (1024 * 1024), sizeof(t) - 2, 0);		t[tlen++] = 'M';		t[tlen] = '\0';	} else if (num && (num / 1024) * 1024 == num) {		ret = longcat(&t, &tlen, num / 1024, sizeof(t) - 2, 0);		t[tlen++] = 'k';		t[tlen] = '\0';	} else {		ret = longcat(&t, &tlen, num, sizeof(t) - 1, 0);	}	if (ret < 0 || !tlen) return NULL;	add_bytes_to_string(string, t, tlen);	return string;}struct string *add_xnum_to_string(struct string *string, int xnum){	unsigned char suff[3] = "\0i";	int d = -1;	/* XXX: I don't completely like the computation of d here. --pasky */	/* Mebi (Mi), 2^20 */	if (xnum >= 1024 * 1024) {		suff[0] = 'M';		d = (xnum / (int) ((int) (1024 * 1024) / (int) 10)) % 10;		xnum /= 1024*1024;	/* Kibi (Ki), 2^10 */	} else if (xnum >= 1024) {		suff[0] = 'K';		d = (xnum / (int) ((int) 1024 / (int) 10)) % 10;		xnum /= 1024;	}	add_long_to_string(string, xnum);	if (xnum < 10 && d != -1) {		add_char_to_string(string, '.');		add_long_to_string(string, d);	}	add_char_to_string(string, ' ');	if (suff[0]) add_to_string(string, suff);	add_char_to_string(string, 'B');	return string;}struct string *add_time_to_string(struct string *string, ttime time){	unsigned char q[64];	int qlen = 0;	time /= 1000;	time &= 0xffffffff;	if (time < 0) time = 0;	/* Days */	if (time >= (24 * 3600)) {		ulongcat(q, &qlen, (time / (24 * 3600)), 5, 0);		q[qlen++] = 'd';		q[qlen++] = ' ';	}	/* Hours and minutes */	if (time >= 3600) {		time %= (24 * 3600);		ulongcat(q, &qlen, (time / 3600), 4, 0);		q[qlen++] = ':';		ulongcat(q, &qlen, ((time / 60) % 60), 2, '0');	} else {		/* Only minutes */		ulongcat(q, &qlen, (time / 60), 2, 0);	}	/* Seconds */	q[qlen++] = ':';	ulongcat(q, &qlen, (time % 60), 2, '0');	add_to_string(string, q);	return string;}#ifdef HAVE_STRFTIMEstruct string *add_date_to_string(struct string *string, unsigned char *fmt, ttime *date){	unsigned char buffer[MAX_STR_LEN];	ttime when_time = date ? *date : time(NULL);	struct tm *when_local = localtime(&when_time);	if (strftime(buffer, sizeof(buffer), fmt, when_local) <= 0)		return NULL;	return add_to_string(string, buffer);}#endif/* Encoders and string changers */struct string *add_string_replace(struct string *string, unsigned char *src, int len,		   unsigned char replaceable, unsigned char replacement){	int oldlength = string->length;	if (!add_bytes_to_string(string, src, len))		return NULL;	for (src = string->source + oldlength; len; len--, src++)		if (*src == replaceable)			*src = replacement;	return string;}struct string *add_html_to_string(struct string *string, unsigned char *src, int len){#define isalphanum(q) (isalnum(q) || (q) == '-' || (q) == '_')	for (; len; len--, src++) {		if (isalphanum(*src) || *src == ' '		    || *src == '.' || *src == ':' || *src == ';') {			add_bytes_to_string(string, src, 1);		} else {			add_bytes_to_string(string, "&#", 2);			add_long_to_string(string, (long) *src);			add_char_to_string(string, ';');		}	}#undef isalphanum	return string;}/* TODO Optimize later --pasky */struct string *add_quoted_to_string(struct string *string, unsigned char *src, int len){	for (; len; len--, src++) {		if (isquote(*src) || *src == '\\')			add_char_to_string(string, '\\');		add_char_to_string(string, *src);	}	return string;}struct string *add_shell_quoted_to_string(struct string *string, unsigned char *src, int len){	add_char_to_string(string, '\'');	for (; len; len--, ++src)		if (*src == '\'')			add_to_string(string, "'\\''");		else			add_char_to_string(string, *src);	add_char_to_string(string, '\'');	return string;}struct string *add_shell_safe_to_string(struct string *string, unsigned char *cmd, int cmdlen){	int prev_safe = 0;	for (; cmdlen; cmdlen--, cmd++) {		if ((*cmd == '-' && prev_safe) ||		    (prev_safe = is_safe_in_shell(*cmd))) {			add_char_to_string(string, *cmd);		} else {			/* XXX: Not all programs we might exec are capable of			 * decoding these.  For some, we should just report			 * an error rather than exec with an encoded string. */			add_char_to_string(string, '%');			add_char_to_string(string, hx((*cmd & 0xf0) >> 4));			add_char_to_string(string, hx(*cmd & 0x0f));		}	}	return string;}longstrtolx(unsigned char *str, unsigned char **end){	long num;	unsigned char postfix;	errno = 0;	num = strtol(str, (char **) end, 10);	if (errno) return 0;	if (!*end) return num;	postfix = toupper(**end);	if (postfix == 'K') {		(*end)++;		if (num < -INT_MAX / 1024) return -INT_MAX;		if (num > INT_MAX / 1024) return INT_MAX;		return num * 1024;	}	if (postfix == 'M') {		(*end)++;		if (num < -INT_MAX / (1024 * 1024)) return -INT_MAX;		if (num > INT_MAX / (1024 * 1024)) return INT_MAX;		return num * (1024 * 1024);	}	return num;}intmonth2num(const unsigned char *str){	unsigned char month[3] = { str[0]|32, str[1]|32, str[2]|32 };	switch (month[0]) {	case 'j': /* jan, jun, jul */		if (month[1] == 'a') {			if (month[2] == 'n') return 0; /* jan */			return -1;		}		if (month[1] == 'u') {			if (month[2] == 'n') return 5; /* jun */			if (month[2] == 'l') return 6; /* jul */		}		return -1;	case 'm': /* mar, may */		if (month[1] == 'a') {			if (month[2] == 'r') return 2; /* mar */			if (month[2] == 'y') return 4; /* may */		}		return -1;	case 'a': /* apr, aug */		if (month[1] == 'p') {			if (month[2] == 'r') return 3; /* apr */			return -1;		}		if (month[1] == 'u' && month[2] == 'g') return 7; /* aug */		return -1;	case 's':		if (month[1] == 'e' && month[2] == 'p') return 8; /* sep */		return -1;	case 'o':		if (month[1] == 'c' && month[2] == 't') return 9; /* oct */		return -1;	case 'n':		if (month[1] == 'o' && month[2] == 'v') return 10; /* nov */		return -1;	case 'd':		if (month[1] == 'e' && month[2] == 'c') return 11; /* dec */		return -1;	case 'f':		if (month[1] == 'e' && month[2] == 'b') return 1; /* feb */		return -1;	default:		return -1;	}}/* This function drops control chars, nbsp char and limit the number of consecutive * space chars to one. It modifies its argument. */voidclr_spaces(unsigned char *str){	unsigned char *s;	unsigned char *dest = str;	assert(str);	for (s = str; *s; s++)		if (*s < ' ' || *s == NBSP_CHAR) *s = ' ';	for (s = str; *s; s++) {		if (*s == ' ' && (dest == str || s[1] == ' ' || !s[1]))			continue;		*dest++ = *s;	}	*dest = '\0';}/* Replace invalid chars in @title with ' ' and trim all starting/ending * spaces. */voidsanitize_title(unsigned char *title){	int len = strlen(title);	if (!len) return;	while (len--) {		if (title[len] < ' ')			title[len] = ' ';	}	trim_chars(title, ' ', NULL);}/* Returns 0 if @url contains invalid chars, 1 if ok. * It trims starting/ending spaces. */intsanitize_url(unsigned char *url){	int len = strlen(url);	if (!len) return 1;	while (len--) {		if (url[len] < ' ')			return 0;	}	trim_chars(url, ' ', NULL);	return 1;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?