File:  [ELWIX - Embedded LightWeight unIX -] / libaitmqtt / src / aitmqtt.c
Revision 1.3: download - view: text, annotated - select for diffs - revision graph
Thu May 30 09:18:33 2013 UTC (11 years ago) by misho
Branches: MAIN
CVS tags: mqtt1_8, mqtt1_7, MQTT1_7, MQTT1_6, HEAD
version 1.6

    1: /*************************************************************************
    2: * (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
    3: *  by Michael Pounov <misho@openbsd-bg.org>
    4: *
    5: * $Author: misho $
    6: * $Id: aitmqtt.c,v 1.3 2013/05/30 09:18:33 misho Exp $
    7: *
    8: **************************************************************************
    9: The ELWIX and AITNET software is distributed under the following
   10: terms:
   11: 
   12: All of the documentation and software included in the ELWIX and AITNET
   13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
   14: 
   15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
   16: 	by Michael Pounov <misho@elwix.org>.  All rights reserved.
   17: 
   18: Redistribution and use in source and binary forms, with or without
   19: modification, are permitted provided that the following conditions
   20: are met:
   21: 1. Redistributions of source code must retain the above copyright
   22:    notice, this list of conditions and the following disclaimer.
   23: 2. Redistributions in binary form must reproduce the above copyright
   24:    notice, this list of conditions and the following disclaimer in the
   25:    documentation and/or other materials provided with the distribution.
   26: 3. All advertising materials mentioning features or use of this software
   27:    must display the following acknowledgement:
   28: This product includes software developed by Michael Pounov <misho@elwix.org>
   29: ELWIX - Embedded LightWeight unIX and its contributors.
   30: 4. Neither the name of AITNET nor the names of its contributors
   31:    may be used to endorse or promote products derived from this software
   32:    without specific prior written permission.
   33: 
   34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
   35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   37: ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   44: SUCH DAMAGE.
   45: */
   46: #include "global.h"
   47: 
   48: 
   49: #pragma GCC visibility push(hidden)
   50: 
   51: int mqtt_Errno;
   52: char mqtt_Error[STRSIZ];
   53: 
   54: #pragma GCC visibility pop
   55: 
   56: // mqtt_GetErrno() Get error code of last operation
   57: int
   58: mqtt_GetErrno()
   59: {
   60: 	return mqtt_Errno;
   61: }
   62: 
   63: // mqtt_GetError() Get error text of last operation
   64: const char *
   65: mqtt_GetError()
   66: {
   67: 	return mqtt_Error;
   68: }
   69: 
   70: // mqtt_SetErr() Set error to variables for internal use!!!
   71: void
   72: mqtt_SetErr(int eno, char *estr, ...)
   73: {
   74: 	va_list lst;
   75: 
   76: 	mqtt_Errno = eno;
   77: 	memset(mqtt_Error, 0, sizeof mqtt_Error);
   78: 	va_start(lst, estr);
   79: 	vsnprintf(mqtt_Error, sizeof mqtt_Error, estr, lst);
   80: 	va_end(lst);
   81: }
   82: 
   83: #pragma GCC visibility push(hidden)
   84: /* _mqtt_readHEADER() read fixed header from MQTT message */
   85: struct mqtthdr *
   86: _mqtt_readHEADER(mqtt_msg_t * __restrict buf, u_char cmd, int *bytes, int *len)
   87: {
   88: 	struct mqtthdr *hdr;
   89: 
   90: 	if (!buf || !buf->msg_base || !buf->msg_len)
   91: 		return NULL;
   92: 
   93: 	hdr = (struct mqtthdr*) buf->msg_base;
   94: 	if (hdr->mqtt_msg.type != cmd) {
   95: 		mqtt_SetErr(EINVAL, "Error:: wrong command #%d should be %d", 
   96: 				hdr->mqtt_msg.type, cmd);
   97: 		return NULL;
   98: 	}
   99: 
  100: 	*len = mqtt_decodeLen(hdr->mqtt_len, bytes);
  101: 	return hdr;
  102: }
  103: #pragma GCC visibility pop
  104: 
  105: 
  106: /*
  107:  * mqtt_msgFree() Free MQTT message
  108:  *
  109:  * @msg = Message buffer
  110:  * @all = !=0 Destroy entire message, if MQTT Message allocated with mqtt_msgAlloc()
  111:  * return: none
  112:  */
  113: void
  114: mqtt_msgFree(mqtt_msg_t ** __restrict msg, int all)
  115: {
  116: 	if (msg && *msg) {
  117: 		if ((*msg)->msg_base) {
  118: 			free((*msg)->msg_base);
  119: 			(*msg)->msg_base = NULL;
  120: 		}
  121: 		if (all) {
  122: 			free(*msg);
  123: 			*msg = NULL;
  124: 		} else
  125: 			(*msg)->msg_len ^= (*msg)->msg_len;
  126: 	}
  127: }
  128: 
  129: /*
  130:  * mqtt_msgAlloc() Allocate memory for MQTT Message
  131:  *
  132:  * @len = >0 Allocate buffer with length
  133:  * return: NULL error or Message, after use must call mqtt_msgFree() with all!=0
  134:  */
  135: mqtt_msg_t *
  136: mqtt_msgAlloc(u_short len)
  137: {
  138: 	mqtt_msg_t *m = NULL;
  139: 
  140: 	m = malloc(sizeof(mqtt_msg_t));
  141: 	if (!m) {
  142: 		LOGERR;
  143: 		return NULL;
  144: 	} else
  145: 		memset(m, 0, sizeof(mqtt_msg_t));
  146: 
  147: 	if (len) {
  148: 		m->msg_len = len;
  149: 		m->msg_base = malloc(m->msg_len);
  150: 		if (!m->msg_base) {
  151: 			LOGERR;
  152: 			free(m);
  153: 			return NULL;
  154: 		} else
  155: 			memset(m->msg_base, 0, m->msg_len);
  156: 	}
  157: 
  158: 	return m;
  159: }
  160: 
  161: /*
  162:  * mqtt_msgRealloc() Reallocate MQTT message buffer
  163:  *
  164:  * @msg = MQTT message
  165:  * @len = new length
  166:  * return: -1 error or >-1 old buffer length
  167:  */
  168: int
  169: mqtt_msgRealloc(mqtt_msg_t * __restrict msg, u_short len)
  170: {
  171: 	void *p = NULL;
  172: 	int ret = 0;
  173: 
  174: 	if (!msg)
  175: 		return -1;
  176: 
  177: 	if (len <= msg->msg_len)
  178: 		return len;
  179: 
  180: 	p = realloc(msg->msg_base, len);
  181: 	if (!p) {
  182: 		LOGERR;
  183: 		return -1;
  184: 	}
  185: 
  186: 	ret = msg->msg_len;
  187: 	msg->msg_len = len;
  188: 	msg->msg_base = p;
  189: 
  190: 	return ret;
  191: }
  192: 
  193: /*
  194:  * mqtt_msgDup() - Duplicate message buffer
  195:  *
  196:  * @msg = Message
  197:  * return: NULL error or !=NULL duplicated message, after use must call mqtt_msgFree() with all!=0
  198:  */
  199: mqtt_msg_t *
  200: mqtt_msgDup(mqtt_msg_t * __restrict msg)
  201: {
  202: 	mqtt_msg_t *m = NULL;
  203: 
  204: 	m = malloc(sizeof(mqtt_msg_t));
  205: 	if (!m) {
  206: 		LOGERR;
  207: 		return NULL;
  208: 	} else
  209: 		memset(m, 0, sizeof(mqtt_msg_t));
  210: 
  211: 	if (msg->msg_len) {
  212: 		m->msg_len = msg->msg_len;
  213: 		m->msg_base = malloc(m->msg_len);
  214: 		if (!m->msg_base) {
  215: 			LOGERR;
  216: 			free(m);
  217: 			return NULL;
  218: 		} else
  219: 			memcpy(m->msg_base, msg->msg_base, m->msg_len);
  220: 	}
  221: 
  222: 	return m;
  223: }
  224: 
  225: /*
  226:  * mqtt_encodeLen() Encode number to MQTT length field
  227:  *
  228:  * @num = number for encode
  229:  * return: -1 error or >-1 length
  230:  */
  231: u_int
  232: mqtt_encodeLen(u_int num)
  233: {
  234: 	register u_int dig, i;
  235: 	u_int ret = 0;
  236: 
  237: 	if (num > 268435455)
  238: 		return (u_int) -1;
  239: 
  240: 	for (i = 0; i < sizeof ret && num > 0; i++) {
  241: 		dig = num % 0x80;
  242: 		num /= 0x80;
  243: 		if (num > 0)
  244: 			dig |= 0x80;
  245: 
  246: 		*((u_char*) &ret + i) = (u_char) dig;
  247: 	}
  248: 
  249: 	return ret;
  250: }
  251: 
  252: /*
  253:  * mqtt_decodeLen() Decode length from MQTT packet
  254:  *
  255:  * @len = length from MQTT header
  256:  * @n = sizeof bytes, if !=NULL
  257:  * return: -1 error, >-1 length of message
  258:  */
  259: u_int
  260: mqtt_decodeLen(void * __restrict len, int * __restrict n)
  261: {
  262: 	register u_int i, dig, mul;
  263: 	u_int ret = 0;
  264: 	u_char *p = (u_char*) len;
  265: 
  266: 	if (!len)
  267: 		return (u_int) -1;
  268: 
  269: 	for (mul = 1, i = 0; i < sizeof ret; i++, mul *= 0x80) {
  270: 		dig = p[i];
  271: 		ret += (dig & 0x7f) * mul;
  272: 
  273: 		if (!(dig & 0x80))
  274: 			break;
  275: 	}
  276: 
  277: 	if (n)
  278: 		*n = (char) (i & 0x7f) + 1;
  279: 	return ret;
  280: }
  281: 
  282: /*
  283:  * mqtt_sizeLen Return sizeof len field
  284:  *
  285:  * @len = length
  286:  * return: -1 error, >-1 sizeof len in bytes
  287:  */
  288: char
  289: mqtt_sizeLen(u_int len)
  290: {
  291: 	register char i;
  292: 	u_char *p = (u_char*) &len;
  293: 
  294: 	if (len > 0xffffff7f)
  295: 		return -1;
  296: 
  297: 	for (i = 0; i < sizeof len; i++)
  298: 		if (!(*(p + i) & 0x80))
  299: 			break;
  300: 
  301: 	return ++i;
  302: }
  303: 
  304: /*
  305:  * mqtt_pktLen() - Get total packet length
  306:  *
  307:  * @hdr = MQTT packet header
  308:  * return: packet length
  309:  */
  310: u_int
  311: mqtt_pktLen(struct mqtthdr * __restrict hdr)
  312: {
  313: 	int siz, n = 0;
  314: 
  315: 	if (!hdr)
  316: 		return 0;
  317: 
  318: 	siz = mqtt_decodeLen(hdr->mqtt_len, &n);
  319: 	siz += sizeof(struct mqtthdr) + n - 1;
  320: 
  321: 	return siz;
  322: }
  323: 
  324: /*
  325:  * mqtt_str2subs Create MQTT subscribe variable from string(s)
  326:  *
  327:  * @csStr = null terminated string array
  328:  * @strnum = copy at most number of strings elements
  329:  * @qoses = QoS elements applied to subscribe variable, 
  330:  * 		count of elements must be equal with csStr elements
  331:  * return: NULL error or != subscribe variables array, must be free after use with mqtt_freeSub()
  332:  */
  333: mqtt_subscr_t *
  334: mqtt_str2subs(const char **csStr, u_short strnum, u_char *qoses)
  335: {
  336: 	mqtt_subscr_t *v;
  337: 	register int i, items;
  338: 	const char **strs;
  339: 
  340: 	if (!csStr)
  341: 		return NULL;
  342: 
  343: 	for (items = 0, strs = csStr; 
  344: 			(!strnum || (strnum && items < strnum)) && *strs; 
  345: 			items++, strs++);
  346: 
  347: 	if (!(v = malloc((items + 1) * sizeof(mqtt_subscr_t)))) {
  348: 		LOGERR;
  349: 		return NULL;
  350: 	} else
  351: 		memset(v, 0, (items + 1) * sizeof(mqtt_subscr_t));
  352: 
  353: 	for (i = 0; i < items; i++) {
  354: 		v[i].sub_topic.msg_len = strlen(csStr[i]);
  355: 		v[i].sub_topic.msg_base = (u_char*) strdup(csStr[i]);
  356: 		if (qoses && qoses[i] < MQTT_QOS_RESERVED)
  357: 			v[i].sub_ret = qoses[i];
  358: 	}
  359: 
  360: 	return v;
  361: }
  362: 
  363: /*
  364:  * mqtt_subFree() Free array from subscribe variables
  365:  *
  366:  * @subs = Subscribe variables
  367:  * return: none
  368:  */
  369: void
  370: mqtt_subFree(mqtt_subscr_t ** __restrict subs)
  371: {
  372: 	mqtt_subscr_t *v;
  373: 
  374: 	if (!subs)
  375: 		return;
  376: 
  377: 	for (v = *subs; v->sub_topic.msg_base; v++) {
  378: 		free(v->sub_topic.msg_base);
  379: 		v->sub_topic.msg_base = NULL;
  380: 		v->sub_topic.msg_len = 0;
  381: 
  382: 		if (v->sub_value.msg_base) {
  383: 			free(v->sub_value.msg_base);
  384: 			v->sub_value.msg_base = NULL;
  385: 			v->sub_value.msg_len = 0;
  386: 		}
  387: 	}
  388: 
  389: 	free(*subs);
  390: 	*subs = NULL;
  391: }
  392: 
  393: /*
  394:  * mqtt_subAlloc() Create array from subscribe variables
  395:  *
  396:  * @num = Number of elements
  397:  * return: NULL error or subscribe array, after use must call mqtt_subFree()
  398:  */
  399: mqtt_subscr_t *
  400: mqtt_subAlloc(u_short num)
  401: {
  402: 	mqtt_subscr_t *s = NULL;
  403: 
  404: 	s = malloc((num + 1) * sizeof(mqtt_subscr_t));
  405: 	if (!s) {
  406: 		LOGERR;
  407: 		return NULL;
  408: 	} else
  409: 		memset(s, 0, (num + 1) * sizeof(mqtt_subscr_t));
  410: 
  411: 	return s;
  412: }
  413: 
  414: /*
  415:  * mqtt_subRealloc() Reallocate array from subscribe variables
  416:  *
  417:  * @subs = Subscribe array
  418:  * @num = Number of elements
  419:  * return: NULL error or subscribe array, after use must call mqtt_subFree()
  420:  */
  421: mqtt_subscr_t *
  422: mqtt_subRealloc(mqtt_subscr_t ** __restrict subs, u_short num)
  423: {
  424: 	mqtt_subscr_t *s = NULL;
  425: 
  426: 	if (!subs)
  427: 		return NULL;
  428: 
  429: 	s = realloc(*subs, (num + 1) * sizeof(mqtt_subscr_t));
  430: 	if (!s) {
  431: 		LOGERR;
  432: 		return NULL;
  433: 	} else {
  434: 		memset(s + num, 0, sizeof(mqtt_subscr_t));
  435: 		*subs = s;
  436: 	}
  437: 
  438: 	return *subs;
  439: }
  440: 
  441: /*
  442:  * mqtt_subCopy() - Copy subscription structure to another one
  443:  *
  444:  * @dst = destination subscription
  445:  * @src = source subscription
  446:  * return: =NULL error or !=NULL successful copied a structure
  447:  */
  448: mqtt_subscr_t *
  449: mqtt_subCopy(mqtt_subscr_t * __restrict dst, mqtt_subscr_t * __restrict src)
  450: {
  451: 	if (!dst || !src)
  452: 		return NULL;
  453: 
  454: 	if (src->sub_topic.msg_base) {
  455: 		dst->sub_topic.msg_base = malloc(src->sub_topic.msg_len + 1);
  456: 		if (!dst->sub_topic.msg_base) {
  457: 			LOGERR;
  458: 			memset(dst, 0, sizeof(mqtt_subscr_t));
  459: 			return NULL;
  460: 		} else {
  461: 			dst->sub_topic.msg_len = src->sub_topic.msg_len;
  462: 			((char*) dst->sub_topic.msg_base)[dst->sub_topic.msg_len] = 0;
  463: 			memcpy(dst->sub_topic.msg_base, src->sub_topic.msg_base, 
  464: 					dst->sub_topic.msg_len);
  465: 		}
  466: 	} else {
  467: 		/*
  468: 		if (dst->sub_topic.msg_base)
  469: 			free(dst->sub_topic.msg_base);
  470: 			*/
  471: 		dst->sub_topic.msg_base = NULL;
  472: 		dst->sub_topic.msg_len = 0;
  473: 	}
  474: 	if (src->sub_value.msg_base) {
  475: 		dst->sub_value.msg_base = malloc(src->sub_value.msg_len + 1);
  476: 		if (!dst->sub_value.msg_base) {
  477: 			LOGERR;
  478: 			if (dst->sub_topic.msg_base)
  479: 				free(dst->sub_topic.msg_base);
  480: 			memset(dst, 0, sizeof(mqtt_subscr_t));
  481: 			return NULL;
  482: 		} else {
  483: 			dst->sub_value.msg_len = src->sub_value.msg_len;
  484: 			((char*) dst->sub_value.msg_base)[dst->sub_value.msg_len] = 0;
  485: 			memcpy(dst->sub_value.msg_base, src->sub_value.msg_base, 
  486: 					dst->sub_value.msg_len);
  487: 		}
  488: 	} else {
  489: 		/*
  490: 		if (dst->sub_value.msg_base)
  491: 			free(dst->sub_value.msg_base);
  492: 			*/
  493: 		dst->sub_value.msg_base = NULL;
  494: 		dst->sub_value.msg_len = 0;
  495: 	}
  496: 
  497: 	dst->sub_ret = src->sub_ret;
  498: 	return dst;
  499: }
  500: 
  501: 
  502: /*
  503:  * mqtt_expandTopic() - Expanding topic to regular expression
  504:  *
  505:  * @csInput = Input topic
  506:  * @psRegEx = Output to regular expression
  507:  * @regexLen = Length of psRegEx
  508:  * @BOL = Begin of Line, if =0 not added
  509:  * @EOL = End of Line, if =0 not appended
  510:  * return: -1 error, 0 nothing expanded or >0 expanded bytes
  511:  */
  512: int
  513: mqtt_expandTopic(const char *csInput, char * __restrict psRegEx, int regexLen, u_char BOL, u_char EOL)
  514: {
  515: 	int ret = 0;
  516: 	register int i;
  517: 	char *pos, *s;
  518: 	const char reROM[] = "[](){}^$\\-|?.+*";
  519: 
  520: 	if (!csInput || !psRegEx || regexLen < 1)
  521: 		return -1;
  522: 	else
  523: 		memset(psRegEx, 0, regexLen);
  524: 
  525: 	/* check # */
  526: 	for (i = 0, pos = (char*) csInput; *pos && i < 2; pos++)
  527: 		if (*pos == '#')
  528: 			i++;
  529: 	if (i == 2) {
  530: 		mqtt_SetErr(EINVAL, "Syntax error, multiple occurrences of #..#");
  531: 		return -1;
  532: 	}
  533: 	if (i == 1 && (pos = strrchr(csInput, '#')))
  534: 		if ((pos != csInput && *(pos - 1) != '/') || *(pos + 1)) {
  535: 			mqtt_SetErr(EINVAL, "Syntax error, bad format of #");
  536: 			return -1;
  537: 		}
  538: 	/* check + */
  539: 	for (pos = (char*) csInput; *pos && (pos = strchr(pos, '+')); pos++)
  540: 		if ((pos != csInput && *(pos - 1) != '/') || (*(pos + 1) && *(pos + 1) != '/')) {
  541: 			mqtt_SetErr(EINVAL, "Syntax error, bad format of +");
  542: 			return -1;
  543: 		}
  544: 
  545: 	/* BUILD REGEX */
  546: 	s = psRegEx;
  547: 	if (BOL) {
  548: 		*s++ = '^';
  549: 		ret++;
  550: 	}
  551: 	for (pos = (char*) csInput; s < psRegEx + regexLen && *pos; s++, pos++) {
  552: 		if (*pos == '#') {
  553: 			strlcat(s, ".*", regexLen - (s - psRegEx));
  554: 			s++;
  555: 			ret++;
  556: 			break;
  557: 		}
  558: 		if (*pos == '+') {
  559: 			if (*(pos + 1)) {
  560: 				strlcat(s, ".*", regexLen - (s - psRegEx));
  561: 				s++;
  562: 				ret++;
  563: 				continue;
  564: 			} else {
  565: 				strlcat(s, ".*/", regexLen - (s - psRegEx));
  566: 				ret += 2;
  567: 				break;
  568: 			}
  569: 		}
  570: 		for (i = 0; i < sizeof reROM - 1; i++)
  571: 			if (*pos == reROM[i] && regexLen - (s - psRegEx) - 1 > 0) {
  572: 				*s++ = '\\';
  573: 				ret++;
  574: 				break;
  575: 			}
  576: 
  577: 		*s = *pos;
  578: 	}
  579: 	if (EOL) {
  580: 		strlcat(psRegEx, "$", regexLen);
  581: 		ret++;
  582: 	}
  583: 
  584: 	return ret;
  585: }
  586: 
  587: /*
  588:  * mqtt_sqlTopic() - Expanding topic to SQL search string
  589:  *
  590:  * @csInput = Input topic
  591:  * @psSQL = Output to SQL search string
  592:  * @sqlLen = Length of psSQL
  593:  * return: -1 error, 0 changed bytes
  594:  */
  595: int
  596: mqtt_sqlTopic(const char *csInput, char * __restrict psSQL, int sqlLen)
  597: {
  598: 	int ret = 0;
  599: 	register int i;
  600: 	char *pos, *s;
  601: 
  602: 	if (!csInput || !psSQL || sqlLen < 1)
  603: 		return -1;
  604: 	else
  605: 		memset(psSQL, 0, sqlLen);
  606: 
  607: 	/* check # */
  608: 	for (i = 0, pos = (char*) csInput; *pos && i < 2; pos++)
  609: 		if (*pos == '#')
  610: 			i++;
  611: 	if (i == 2) {
  612: 		mqtt_SetErr(EINVAL, "Syntax error, multiple occurrences of #..#");
  613: 		return -1;
  614: 	}
  615: 	if (i == 1 && (pos = strrchr(csInput, '#')))
  616: 		if ((pos != csInput && *(pos - 1) != '/') || *(pos + 1)) {
  617: 			mqtt_SetErr(EINVAL, "Syntax error, bad format of #");
  618: 			return -1;
  619: 		}
  620: 	/* check + */
  621: 	for (pos = (char*) csInput; *pos && (pos = strchr(pos, '+')); pos++)
  622: 		if ((pos != csInput && *(pos - 1) != '/') || (*(pos + 1) && *(pos + 1) != '/')) {
  623: 			mqtt_SetErr(EINVAL, "Syntax error, bad format of +");
  624: 			return -1;
  625: 		}
  626: 
  627: 	/* BUILD SEARCH STRING */
  628: 	s = psSQL;
  629: 	for (pos = (char*) csInput; s < psSQL + sqlLen && *pos; s++, pos++) {
  630: 		if (*pos == '#') {
  631: 			*s = '%';
  632: 			s++;
  633: 			ret++;
  634: 			break;
  635: 		}
  636: 		if (*pos == '+') {
  637: 			if (*(pos + 1)) {
  638: 				*s = '%';
  639: 				ret++;
  640: 				continue;
  641: 			} else {
  642: 				strlcat(s, "%/", sqlLen - (s - psSQL));
  643: 				ret += 2;
  644: 				break;
  645: 			}
  646: 		}
  647: 		/*
  648: 		for (i = 0; i < sizeof reROM - 1; i++)
  649: 			if (*pos == reROM[i] && regexLen - (s - psRegEx) - 1 > 0) {
  650: 				*s++ = '\\';
  651: 				ret++;
  652: 				break;
  653: 			}
  654: 			*/
  655: 
  656: 		*s = *pos;
  657: 	}
  658: 
  659: 	return ret;
  660: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>