Пример #1
0
static std::string
format_key_and_json_value(std::string const &key,
                          nlohmann::json const &value) {
  return (boost::format{"%1%:%2%"} % escape(key) % escape(format_json_value(value))).str();
}
Пример #2
0
SDF_Symbol PTSymbolToSDFSymbol(PT_Symbol ptSymbol)
{
  SDF_Symbol result;

  if (PT_isSymbolLit(ptSymbol)) {
    char *str = PT_getSymbolString(ptSymbol);
    char *qstr = escape(str, "\"\\", QUOTED);
    SDF_Literal lit = SDF_makeLiteralQlit(SDF_makeQLiteralQuoted(SDF_makeCHARLISTString(qstr)));
    free(qstr);

    result = SDF_makeSymbolLit(lit);
  }
  else if (PT_isSymbolCf(ptSymbol)
	   || PT_isSymbolLex(ptSymbol)
	   || PT_isSymbolVarSym(ptSymbol)) {
    result = PTSymbolToSDFSymbol(PT_getSymbolSymbol(ptSymbol));
  }
  else if (PT_isSymbolEmpty(ptSymbol)) {
    result = SDF_makeSymbolEmpty(SDF_makeLayoutEmpty());
  }
  else if (PT_isSymbolSeq(ptSymbol)) {
    PT_Symbols ptSymbols = PT_getSymbolSymbols(ptSymbol);
    PT_Symbol ptHead = PT_getSymbolsHead(ptSymbols);
    SDF_Symbol sdfHead = PTSymbolToSDFSymbol(ptHead);
    PT_Symbols ptTail = PT_getSymbolsTail(ptSymbols);
 
    if (PT_isSymbolsEmpty(ptTail)) {
      ATabort("PTSymbolToSDFSymbol: empty tail in %s\n",
              PT_yieldSymbol(ptSymbol));

      result = NULL;
    }
    else {
      SDF_SymbolTail sdfSymbolTail = 
        (SDF_SymbolTail)PTSymbolsToSDFSymbolList(ptTail);

      result = SDF_makeSymbolSeq(SDF_makeLayoutEmpty(),
                                 sdfHead, 
                                 SDF_makeLayoutSpace(),
                                 sdfSymbolTail,
                                 SDF_makeLayoutEmpty());
    }
  }
  else if (PT_isSymbolOpt(ptSymbol)) {
    SDF_Symbol sdfSymbol = PTSymbolToSDFSymbol(PT_getSymbolSymbol(ptSymbol));

    result = SDF_makeSymbolOpt(sdfSymbol, SDF_makeLayoutEmpty());
  }
  else if (PT_isSymbolAlt(ptSymbol)) {
    SDF_Symbol sdfLhs = PTSymbolToSDFSymbol(PT_getSymbolLhs(ptSymbol));
    SDF_Symbol sdfRhs = PTSymbolToSDFSymbol(PT_getSymbolRhs(ptSymbol));

    result = SDF_makeSymbolAlt(sdfLhs, 
                               SDF_makeLayoutEmpty(), 
                               SDF_makeLayoutEmpty(),
                               sdfRhs);
  }
  else if (PT_isSymbolTuple(ptSymbol)) {
    SDF_Symbol sdfHead = PTSymbolToSDFSymbol(PT_getSymbolHead(ptSymbol));
    SDF_SymbolRest sdfRest = PTSymbolsToSDFSymbolRest(PT_getSymbolRest(ptSymbol));

    result = SDF_makeSymbolTuple(SDF_makeLayoutEmpty(),
                                 sdfHead, 
                                 SDF_makeLayoutEmpty(), 
                                 SDF_makeLayoutEmpty(),
                                 sdfRest,
                                 SDF_makeLayoutEmpty());
  }
  else if (PT_isSymbolSort(ptSymbol)) {
    char *str = PT_getSymbolSort(ptSymbol);
    SDF_Sort sort = SDF_makeSortMoreChars(SDF_makeCHARLISTString(str));

    result = SDF_makeSymbolSort(sort);
  }
  else if (PT_isSymbolIterPlus(ptSymbol)) { 
    SDF_Symbol sdfSymbol = PTSymbolToSDFSymbol(PT_getSymbolSymbol(ptSymbol));

    result = SDF_makeSymbolIter(sdfSymbol, SDF_makeLayoutEmpty());
  }
  else if (PT_isSymbolIterStar(ptSymbol)) { 
    SDF_Symbol sdfSymbol = PTSymbolToSDFSymbol(PT_getSymbolSymbol(ptSymbol));

    result = SDF_makeSymbolIterStar(sdfSymbol, SDF_makeLayoutEmpty());
  }
  else if (PT_isSymbolIterPlusSep(ptSymbol)) { 
    SDF_Symbol sdfSymbol = PTSymbolToSDFSymbol(PT_getSymbolSymbol(ptSymbol));
    SDF_Symbol sdfSep = PTSymbolToSDFSymbol(PT_getSymbolSeparator(ptSymbol));

    result = SDF_makeSymbolIterSep(SDF_makeLayoutEmpty(),
                                   sdfSymbol, 
                                   SDF_makeLayoutSpace(),
                                   sdfSep,
                                   SDF_makeLayoutEmpty(),
                                   SDF_makeLayoutEmpty());
  }
  else if (PT_isSymbolIterStarSep(ptSymbol)) { 
    SDF_Symbol sdfSymbol = PTSymbolToSDFSymbol(PT_getSymbolSymbol(ptSymbol));
    SDF_Symbol sdfSep = PTSymbolToSDFSymbol(PT_getSymbolSeparator(ptSymbol));

    result = SDF_makeSymbolIterStarSep(SDF_makeLayoutEmpty(),
                                       sdfSymbol, 
                                       SDF_makeLayoutSpace(),
                                       sdfSep,
                                       SDF_makeLayoutEmpty(),
                                       SDF_makeLayoutEmpty());
  }
  else if (PT_isSymbolIterN(ptSymbol)) { 
    char str[BUFSIZ];
    SDF_Symbol sdfSymbol = PTSymbolToSDFSymbol(PT_getSymbolSymbol(ptSymbol));
    int nr = PT_getSymbolNumber(ptSymbol);
    SDF_NatCon sdfNatCon;
    sprintf(str, "%d", nr);
    
    sdfNatCon = SDF_makeNatConDigits(SDF_makeCHARLISTString(str));

    result = SDF_makeSymbolIterN(sdfSymbol, 
                                 SDF_makeLayoutSpace(),
                                 sdfNatCon,
                                 SDF_makeLayoutEmpty());
  }
  else if (PT_isSymbolIterSepN(ptSymbol)) { 
    char str[BUFSIZ];
    SDF_Symbol sdfSymbol = PTSymbolToSDFSymbol(PT_getSymbolSymbol(ptSymbol));
    SDF_Symbol sdfSep = PTSymbolToSDFSymbol(PT_getSymbolSeparator(ptSymbol));
    int nr = PT_getSymbolNumber(ptSymbol);
    SDF_NatCon sdfNatCon;
    sprintf(str, "%d", nr);
    
    sdfNatCon = SDF_makeNatConDigits(SDF_makeCHARLISTString(str));

    result = SDF_makeSymbolIterSepN(SDF_makeLayoutEmpty(),
                                    sdfSymbol, 
                                    SDF_makeLayoutSpace(),
                                    sdfSep,
                                    SDF_makeLayoutEmpty(),
                                    SDF_makeLayoutEmpty(),
                                    sdfNatCon,
                                    SDF_makeLayoutEmpty());
  }
  else if (PT_isSymbolLayout(ptSymbol)) {
    ATabort("PTSymbolToSDFSymbol: layout.\n");
    result = NULL;
  }
  else {
    ATabort("PTSymbolToSDFSymbol: unable to convert symbol %t: %s\n",
            ptSymbol, PT_yieldSymbol(ptSymbol));

    result = NULL;
  }
  return result;
}
Пример #3
0
std::string& escape(std::string& str)
{
	static const std::string special_chars("#@{}+-,\\*=");
	return escape(str, special_chars);
}
bool ofParameterGroup::contains(string name) {
    return obj->parametersIndex.find(escape(name))!=obj->parametersIndex.end();
}
Пример #5
0
void 
NumberFormatRoundTripTest::test(NumberFormat *fmt, const Formattable& value)
{
    fmt->setMaximumFractionDigits(999);
    if(fmt->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
        ((DecimalFormat *)fmt)->setRoundingIncrement(0.0);
    }
    UErrorCode status = U_ZERO_ERROR;
    UnicodeString s, s2, temp;
    if(isDouble(value))
        s = fmt->format(value.getDouble(), s);
    else
        s = fmt->format(value.getLong(), s);

    Formattable n;
    UBool show = verbose;
    if(DEBUG)
        logln(/*value.getString(temp) +*/ " F> " + escape(s));

    fmt->parse(s, n, status);
    failure(status, "fmt->parse");
    if(DEBUG) 
        logln(escape(s) + " P> " /*+ n.getString(temp)*/);

    if(isDouble(n))
        s2 = fmt->format(n.getDouble(), s2);
    else
        s2 = fmt->format(n.getLong(), s2);
    
    if(DEBUG) 
        logln(/*n.getString(temp) +*/ " F> " + escape(s2));

    if(STRING_COMPARE) {
        if (s != s2) {
            errln("*** STRING ERROR \"" + escape(s) + "\" != \"" + escape(s2) + "\"");
            show = TRUE;
        }
    }

    if(EXACT_NUMERIC_COMPARE) {
        if(value != n) {
            errln("*** NUMERIC ERROR");
            show = TRUE;
        }
    }
    else {
        // Compute proportional error
        double error = proportionalError(value, n);

        if(error > MAX_ERROR) {
            errln(UnicodeString("*** NUMERIC ERROR ") + error);
            show = TRUE;
        }

        if (error > max_numeric_error) 
            max_numeric_error = error;
        if (error < min_numeric_error) 
            min_numeric_error = error;
    }

    if (show) {
        errln(/*value.getString(temp) +*/ typeOf(value, temp) + " F> " +
            escape(s) + " P> " + (n.getType() == Formattable::kDouble ? n.getDouble() : (double)n.getLong())
            /*n.getString(temp) */ + typeOf(n, temp) + " F> " +
            escape(s2));
    }
}
int ofParameterGroup::getPosition(string name) const {
    if(obj->parametersIndex.find(escape(name))!=obj->parametersIndex.end())
        return obj->parametersIndex.find(escape(name))->second;
    return -1;
}
ofAbstractParameter & ofParameterGroup::get(string name) const {
    map<string,int>::const_iterator it = obj->parametersIndex.find(escape(name));
    int index = it->second;
    return get(index);
}
Пример #8
0
// returns -1 on error, >0 on success
int8_t GSwifi::request(GSwifi::GSMETHOD method, const char *path, const char *body, uint16_t length, GSwifi::GSResponseHandler handler, uint8_t timeout, uint8_t is_binary) {
    char *cmd;

#ifdef TESTER
    // Tester only requests against limited AP test target
    // DNSLOOKUP should fail, because it's in limitedAP mode, ignore it.
    sprintf( ipaddr_, "%s", "192.168.1.1" );
#else
    cmd = PB("AT+DNSLOOKUP=" DOMAIN,1);
    command(cmd, GSCOMMANDMODE_DNSLOOKUP);
#endif

    // modified by eqiglii 2015-12-12
    if ( strstr (path, "proxy.php") ) {  // this means it is my temperature reporting service, which should go via my proxy server
      sprintf( ipaddr_, "%s", "192.168.0.18" ); // my raspberrypi IP address, it changes depending on connected home devices
    }    
    // end by eqiglii 2015-12-12
    
    // don't fail fatally on dnslookup failure,
    // we cache our server's ipaddress anyway
    // it happens randomly
    if (ipaddr_[ 0 ] == 0) {
        // but if it has not been resolved yet,
        // we must be not connected to internet,
        // let's show yellow blink on colorled
        Serial.println ("DOMAIN is not resolved to ipaddr"); // print log, added by eqiglii
        clear();
        on_disconnect_();
        return -1;
    }
    
    cmd = PB("AT+NCTCP=",1);
    strcpy( cmd+9, ipaddr_ );
#ifdef TESTER
    strcpy( cmd+9+strlen(ipaddr_), ",80");
#else
    // modified by eqiglii 2015-12-12
    if ( strstr (path, "proxy.php") ) {  // this means it is my temperature reporting service, which should go via my proxy server
      strcpy( cmd+9+strlen(ipaddr_), ",80");
    }
    else { // this means it is normal IRKit post data
      strcpy( cmd+9+strlen(ipaddr_), ",443");
    }
#endif

    connected_cid_ = CID_UNDEFINED;
    command(cmd, GSCOMMANDMODE_CONNECT);
    int8_t cid = connected_cid_;
    char   xid = i2x(cid);

    if (did_timeout_) {
        return -1;
    }
    if ((0 <= cid) && (cid <= 16)) {
        // OK
    }
    else {
        return -1;
    }

    handlers_[ cid ] = handler;

#ifndef TESTER
    // modified by eqiglii 2015-12-12
    if ( strstr (path, "proxy.php") == NULL ) {  // this means it is normal IRKit post data, NOT my temperature reporting service
      cmd = PB("AT+SSLOPEN=%,cacert",1);
      cmd[ 11 ] = xid;
      command(cmd, GSCOMMANDMODE_NORMAL);
    }
#endif

    // disable TCP_MAXRT and TCP_KEEPALIVE_X, because these commands takes some time to issue,
    // and GS1011MIPS denies short TCP_KEEPALIVE_INTVL,
    // and our server (currently Heroku) disconnects connections after 30seconds,
    // and it's difficult to handle incoming requests while sending these.

    // TCP_MAXRT = 10
    // AT+SETSOCKOPT=0,6,10,10,4
    // cmd = PB("AT+SETSOCKOPT=%,6,10,10,4",1);
    // cmd[ 14 ] = xid;
    // command(cmd, GSCOMMANDMODE_NORMAL);

    // Enable TCP_KEEPALIVE on this socket
    // AT+SETSOCKOPT=0,65535,8,1,4
    // cmd = PB("AT+SETSOCKOPT=%,65535,8,1,4",1);
    // cmd[ 14 ] = xid;
    // command(cmd, GSCOMMANDMODE_NORMAL);

    // TCP_KEEPALIVE_PROBES = 2
    // AT+SETSOCKOPT=0,6,4005,2,4
    // cmd = PB("AT+SETSOCKOPT=%,6,4005,2,4",1);
    // cmd[ 14 ] = xid;
    // command(cmd, GSCOMMANDMODE_NORMAL);

    // TCP_KEEPALIVE_INTVL = 150
    // AT+SETSOCKOPT=0,6,4001,150,4
    // mysteriously, GS1011MIPS denies with "ERROR: INVALID INPUT" for seconds less than 150
    // cmd = PB("AT+SETSOCKOPT=%,6,4001,150,4",1);
    // cmd[ 14 ] = xid;
    // command(cmd, GSCOMMANDMODE_NORMAL);
    // if (did_timeout_) {
    //     return -1;
    // }

    cmd = PB("S0",1);
    cmd[ 1 ]  = xid;
    escape( cmd );

    if (method == GSMETHOD_POST) {
        serial_->print(P("POST "));
    }
    else {
        serial_->print(P("GET "));
    }
    serial_->print(path);
    serial_->print(P(" HTTP/1.1\r\nUser-Agent: IRKit/"));
    serial_->println(version);
    
    // modified by eqiglii 2015-12-12
    if ( strstr (path, "proxy.php") ) {  // this means it is my temperature reporting service, which should go via my proxy server
      serial_->println("Host: 192.168.0.18"); // my raspberrypi IP address, it changes depending on connected home devices
      //serial_->println("Host: raspberrypi.local"); // this does NOT work
    }
    else {  // this means it is normal IRKit service
      serial_->println("Host: " DOMAIN);
    }
    // end by eqiglii 2015-12-12
     
    //serial_->println("Host: " DOMAIN);

    if (method == GSMETHOD_POST) {
        serial_->print(P("Content-Length: "));
        serial_->println( is_binary ? base64_length(length) : length );

        serial_->println("Content-Type: application/x-www-form-urlencoded\r\n");
        if (is_binary) {
            base64_encode((const uint8_t*)body, length, &base64encoded);
        }
        else {
            serial_->print(body);
        }
    }
    else {
        serial_->println();
    }

    // we're long polling here, to receive other events, we're going back to our main loop
    // ignore timeout, we always timeout here
    escape( "E" );

    TIMER_START(timers_[cid], timeout);

    return cid;
}
Пример #9
0
int8_t GSwifi::writeEnd () {
    escape( "E" );
}
Пример #10
0
static char *
printf_doformat(char *start, int *rval)
{
	static const char skip1[] = "#'-+ 0";
	static const char skip2[] = "0123456789";
	char *fmt;
	int fieldwidth, haveprec, havewidth, mod_ldbl, precision;
	char convch, nextch;

	fmt = start + 1;
	/* skip to field width */
	fmt += strspn(fmt, skip1);
	if (*fmt == '*') {
		if (getint(&fieldwidth))
			return (NULL);
		havewidth = 1;
		++fmt;
	} else {
		havewidth = 0;

		/* skip to possible '.', get following precision */
		fmt += strspn(fmt, skip2);
	}
	if (*fmt == '.') {
		/* precision present? */
		++fmt;
		if (*fmt == '*') {
			if (getint(&precision))
				return (NULL);
			haveprec = 1;
			++fmt;
		} else {
			haveprec = 0;

			/* skip to conversion char */
			fmt += strspn(fmt, skip2);
		}
	} else
		haveprec = 0;
	if (!*fmt) {
		warnx("missing format character");
		return (NULL);
	}

	/*
	 * Look for a length modifier.  POSIX doesn't have these, so
	 * we only support them for floating-point conversions, which
	 * are extensions.  This is useful because the L modifier can
	 * be used to gain extra range and precision, while omitting
	 * it is more likely to produce consistent results on different
	 * architectures.  This is not so important for integers
	 * because overflow is the only bad thing that can happen to
	 * them, but consider the command  printf %a 1.1
	 */
	if (*fmt == 'L') {
		mod_ldbl = 1;
		fmt++;
		if (!strchr("aAeEfFgG", *fmt)) {
			warnx("bad modifier L for %%%c", *fmt);
			return (NULL);
		}
	} else {
		mod_ldbl = 0;
	}

	convch = *fmt;
	nextch = *++fmt;
	*fmt = '\0';
	switch (convch) {
	case 'b': {
		size_t len;
		char *p;
		int getout;

		p = strdup(getstr());
		if (p == NULL) {
			warnx("%s", strerror(ENOMEM));
			return (NULL);
		}
		getout = escape(p, 0, &len);
		*(fmt - 1) = 's';
		PF(start, p);
		*(fmt - 1) = 'b';
		free(p);
		if (getout)
			return (fmt);
		break;
	}
	case 'c': {
		char p;

		p = getchr();
		PF(start, p);
		break;
	}
	case 's': {
		const char *p;

		p = getstr();
		PF(start, p);
		break;
	}
	case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
		char *f;
		intmax_t val;
		uintmax_t uval;
		int signedconv;

		signedconv = (convch == 'd' || convch == 'i');
		if ((f = mknum(start, convch)) == NULL)
			return (NULL);
		if (getnum(&val, &uval, signedconv))
			*rval = 1;
		if (signedconv)
			PF(f, val);
		else
			PF(f, uval);
		break;
	}
	case 'e': case 'E':
	case 'f': case 'F':
	case 'g': case 'G':
	case 'a': case 'A': {
		long double p;

		if (getfloating(&p, mod_ldbl))
			*rval = 1;
		if (mod_ldbl)
			PF(start, p);
		else
			PF(start, (double)p);
		break;
	}
	default:
		warnx("illegal format character %c", convch);
		return (NULL);
	}
	*fmt = nextch;
	return (fmt);
}
Пример #11
0
int
main(int argc, char *argv[])
{
	size_t len;
	int chopped, end, rval;
	char *format, *fmt, *start;
#ifndef SHELL
	int ch;

	(void) setlocale(LC_ALL, "");
#endif

#ifdef SHELL
	nextopt("");
	argc -= argptr - argv;
	argv = argptr;
#else
	while ((ch = getopt(argc, argv, "")) != -1)
		switch (ch) {
		case '?':
		default:
			usage();
			return (1);
		}
	argc -= optind;
	argv += optind;
#endif

	if (argc < 1) {
		usage();
		return (1);
	}

#ifdef SHELL
	INTOFF;
#endif
	/*
	 * Basic algorithm is to scan the format string for conversion
	 * specifications -- once one is found, find out if the field
	 * width or precision is a '*'; if it is, gather up value.  Note,
	 * format strings are reused as necessary to use up the provided
	 * arguments, arguments of zero/null string are provided to use
	 * up the format string.
	 */
	fmt = format = *argv;
	chopped = escape(fmt, 1, &len);		/* backslash interpretation */
	rval = end = 0;
	gargv = ++argv;
	for (;;) {
		start = fmt;
		while (fmt < format + len) {
			if (fmt[0] == '%') {
				fwrite(start, 1, fmt - start, stdout);
				if (fmt[1] == '%') {
					/* %% prints a % */
					putchar('%');
					fmt += 2;
				} else {
					fmt = printf_doformat(fmt, &rval);
					if (fmt == NULL) {
#ifdef SHELL
						INTON;
#endif
						return (1);
					}
					end = 0;
				}
				start = fmt;
			} else
				fmt++;
		}

		if (end == 1) {
			warnx("missing format character");
#ifdef SHELL
			INTON;
#endif
			return (1);
		}
		fwrite(start, 1, fmt - start, stdout);
		if (chopped || !*gargv) {
#ifdef SHELL
			INTON;
#endif
			return (rval);
		}
		/* Restart at the beginning of the format string. */
		fmt = format;
		end = 1;
	}
	/* NOTREACHED */
}
Пример #12
0
int main(int argc, char **argv) {

    Calendar *cal;
    DateFormat *fmt;
    DateFormat *defFmt;
    Transliterator *greek_latin;
    Transliterator *rbtUnaccent;
    Transliterator *unaccent;
    UErrorCode status = U_ZERO_ERROR;
    Locale greece("el", "GR");
    UnicodeString str, str2;

    // Create a calendar in the Greek locale
    cal = Calendar::createInstance(greece, status);
    check(status, "Calendar::createInstance");

    // Create a formatter
    fmt = DateFormat::createDateInstance(DateFormat::kFull, greece);
    fmt->setCalendar(*cal);

    // Create a default formatter
    defFmt = DateFormat::createDateInstance(DateFormat::kFull);
    defFmt->setCalendar(*cal);

    // Create a Greek-Latin Transliterator
    greek_latin = Transliterator::createInstance("Greek-Latin");
    if (greek_latin == 0) {
        printf("ERROR: Transliterator::createInstance() failed\n");
        exit(1);
    }

    // Create a custom Transliterator
    rbtUnaccent = new RuleBasedTransliterator("RBTUnaccent",
                                              UNACCENT_RULES,
                                              UTRANS_FORWARD,
                                              status);
    check(status, "RuleBasedTransliterator::ct");

    // Create a custom Transliterator
    unaccent = new UnaccentTransliterator();

    // Loop over various months
    for (int32_t month = Calendar::JANUARY;
         month <= Calendar::DECEMBER;
         ++month) {

        // Set the calendar to a date
        cal->clear();
        cal->set(1999, month, 4);
        
        // Format the date in default locale
        str.remove();
        defFmt->format(cal->getTime(status), str, status);
        check(status, "DateFormat::format");
        printf("Date: ");
        uprintf(escape(str));
        printf("\n");
        
        // Format the date for Greece
        str.remove();
        fmt->format(cal->getTime(status), str, status);
        check(status, "DateFormat::format");
        printf("Greek formatted date: ");
        uprintf(escape(str));
        printf("\n");
        
        // Transliterate result
        greek_latin->transliterate(str);
        printf("Transliterated via Greek-Latin: ");
        uprintf(escape(str));
        printf("\n");
        
        // Transliterate result
        str2 = str;
        rbtUnaccent->transliterate(str);
        printf("Transliterated via RBT unaccent: ");
        uprintf(escape(str));
        printf("\n");

        unaccent->transliterate(str2);
        printf("Transliterated via normalizer unaccent: ");
        uprintf(escape(str2));
        printf("\n\n");
    }

    // Clean up
    delete fmt;
    delete cal;
    delete greek_latin;
    delete unaccent;
    delete rbtUnaccent;

    printf("Exiting successfully\n");
    return 0;
}
Пример #13
0
main()
{
	char s[20] = " afeef	ebrahim  ";
	char t[20] ;
	escape(s,t);
}
Пример #14
0
/**
 * takes a richtext string and heuristically adds links for uris of common protocols
 * @return a richtext string with link markup added
 */
QString TextUtil::linkify(const QString &in)
{
	QString out = in;
	int x1, x2;
	bool isUrl, isAtStyle;
	QString linked, link, href;

	for(int n = 0; n < (int)out.length(); ++n) {
		isUrl = false;
		isAtStyle = false;
		x1 = n;

		if(linkify_pmatch(out, n, "xmpp:")) {
			n += 5;
			isUrl = true;
			href = "";
		}
		else if(linkify_pmatch(out, n, "mailto:")) {
			n += 7;
			isUrl = true;
			href = "";
		}
		else if(linkify_pmatch(out, n, "http://")) {
			n += 7;
			isUrl = true;
			href = "";
		}
		else if(linkify_pmatch(out, n, "https://")) {
			n += 8;
			isUrl = true;
			href = "";
		}
		else if(linkify_pmatch(out, n, "ftp://")) {
			n += 6;
			isUrl = true;
			href = "";
		}
		else if(linkify_pmatch(out, n, "news://")) {
			n += 7;
			isUrl = true;
			href = "";
		}
		else if (linkify_pmatch(out, n, "ed2k://")) {
			n += 7;
			isUrl = true;
			href = "";
		}
		else if (linkify_pmatch(out, n, "magnet:")) {
			n += 7;
			isUrl = true;
			href = "";
		}
		else if(linkify_pmatch(out, n, "www.")) {
			isUrl = true;
			href = "http://";
		}
		else if(linkify_pmatch(out, n, "ftp.")) {
			isUrl = true;
			href = "ftp://";
		}
		else if(linkify_pmatch(out, n, "@")) {
			isAtStyle = true;
			href = "x-psi-atstyle:";
		}

		if(isUrl) {
			// make sure the previous char is not alphanumeric
			if(x1 > 0 && out.at(x1-1).isLetterOrNumber())
				continue;

			// find whitespace (or end)
			QMap<QChar, int> brackets;
			brackets['('] = brackets[')'] = brackets['['] = brackets[']'] = brackets['{'] = brackets['}'] = 0;
			QMap<QChar, QChar> openingBracket;
			openingBracket[')'] = '(';
			openingBracket[']'] = '[';
			openingBracket['}'] = '{';
			for(x2 = n; x2 < (int)out.length(); ++x2) {
				if(out.at(x2).isSpace() || linkify_isOneOf(out.at(x2), "\"\'`<>")
					|| linkify_pmatch(out, x2, "&quot;")  || linkify_pmatch(out, x2, "&apos;")
					|| linkify_pmatch(out, x2, "&gt;") || linkify_pmatch(out, x2, "&lt;") ) {
					break;
				}
				if(brackets.keys().contains(out.at(x2))) {
					++brackets[out.at(x2)];
				}
			}
			int len = x2-x1;
			QString pre = resolveEntities(out.mid(x1, x2-x1));

			// go backward hacking off unwanted punctuation
			int cutoff;
			for(cutoff = pre.length()-1; cutoff >= 0; --cutoff) {
				if(!linkify_isOneOf(pre.at(cutoff), "!?,.()[]{}<>\""))
					break;
				if(linkify_isOneOf(pre.at(cutoff), ")]}")
					&& brackets[pre.at(cutoff)] - brackets[openingBracket[pre.at(cutoff)]] <= 0 ) {
					break;	// in theory, there could be == above, but these are urls, not math ;)
				}
				if(brackets.keys().contains(pre.at(cutoff))) {
					--brackets[pre.at(cutoff)];
				}

			}
			++cutoff;
			//++x2;

			link = pre.mid(0, cutoff);
			if(!linkify_okUrl(link)) {
				n = x1 + link.length();
				continue;
			}
			href += link;
			// attributes need to be encoded too.
			href = escape(href);
			href = linkify_htmlsafe(href);
			//printf("link: [%s], href=[%s]\n", link.latin1(), href.latin1());
			QColor lcolor=PsiOptions::instance()->getOption("options.ui.look.colors.chat.link-color").toString();
			linked = QString("<a href=\"%1\" style=\"color:"+lcolor.name()+"\">").arg(href) + escape(link) + "</a>" + escape(pre.mid(cutoff));
			out.replace(x1, len, linked);
			n = x1 + linked.length() - 1;
		}
		else if(isAtStyle) {
			// go backward till we find the beginning
			if(x1 == 0)
				continue;
			--x1;
			for(; x1 >= 0; --x1) {
				if(!linkify_isOneOf(out.at(x1), "_.-+") && !out.at(x1).isLetterOrNumber())
					break;
			}
			++x1;

			// go forward till we find the end
			x2 = n + 1;
			for(; x2 < (int)out.length(); ++x2) {
				if(!linkify_isOneOf(out.at(x2), "_.-+") && !out.at(x2).isLetterOrNumber())
					break;
			}

			int len = x2-x1;
			link = out.mid(x1, len);
			//link = resolveEntities(link);

			if(!linkify_okEmail(link)) {
				n = x1 + link.length();
				continue;
			}

			href += link;
			//printf("link: [%s], href=[%s]\n", link.latin1(), href.latin1());
			QColor mcolor=PsiOptions::instance()->getOption("options.ui.look.colors.chat.mailto-color").toString();
			linked = QString("<a href=\"%1\" style=\"color:"+mcolor.name()+"\">").arg(href) + link + "</a>";
			out.replace(x1, len, linked);
			n = x1 + linked.length() - 1;
		}
	}

	return out;
}