Package: src/packages/strutil.fdoc

String Support Utilities.

key file
flx_strutil.hpp share/lib/rtl/flx_strutil.hpp
flx_strutil.cpp share/src/strutil/flx_strutil.cpp
flx_i18n.hpp share/lib/rtl/flx_i18n.hpp
flx_i18n.cpp share/src/strutil/flx_i18n.cpp
unix_flx_strutil.fpc $PWD/src/config/unix/flx_strutil.fpc
win_flx_strutil.fpc $PWD/src/config/win/flx_strutil.fpc
flx_i18n.fpc $PWD/src/config/flx_i18n.fpc
flx_strutil_config.hpp share/lib/rtl/flx_strutil_config.hpp
flx_strutil.py $PWD/buildsystem/flx_strutil.py

String utilities

//[flx_strutil.hpp]

#ifndef __FLX_STRUTIL_HPP_
#define __FLX_STRUTIL_HPP_

#include <string>
#include <sstream>
#include <iomanip>
#include <iostream>
#include <cstdarg>
#include <cstdlib>
#include <cstring>
#include <typeinfo>

#include "flx_strutil_config.hpp"

//RF: was only to commented out to fix macosx problem,
//but lets see what happens to all the other builds.
//#ifndef MACOSX
//template class RTL_EXTERN std::basic_string<char>;
//#endif

namespace flx { namespace rtl { namespace strutil {
  using namespace std;
  template<class T>
  basic_string<T> mul(basic_string<T> s, int n) {
    basic_string<T> r = "";
    while(n--) r+=s;
    return r;
  }

  // normalise string positions Python style
  // note substr requires 0<=b<=size, 0<=n,
  // however n>size is OK
  template<class T>
  basic_string<T> substr(basic_string<T> const &s, int b, int e)
  {
    int n = s.size();
    if(b<0)  b=b+n;
    if(b<0)  b=0;
    if(b>=n) b=n;
    if(e<0)  e=e+n;
    if(e<0)  e=0;
    if(e>=n) e=n;
    int m =  e-b;
    if(m<0)  m=0;
    return s.substr(b,m);
  }

  template<class T>
  T subscript(basic_string<T> const &s, int i)
  {
    int n = s.size();
    if(i<0)  i=i+n;
    return i<0 || i >= n ? T(0) : s[i];
  }

  template<class T>
  string str(T const &t) {
    std::ostringstream x;
    x << t;
    return x.str();
  }
  template<class T>
  string fmt_hex(T const &t) {
    std::ostringstream x;
    x << "0x" << std::hex << t << std::dec;
    return x.str();
  }


  template<class T>
  string fmt_default(T const &t, int w, int p) {
    std::ostringstream x;
    x << std::setw(w) << std::setprecision(p) << t;
    return x.str();
  }

  template<class T>
  string fmt_fixed(T const &t, int w, int p) {
    std::ostringstream x;
    x << std::fixed << std::setw(w) << std::setprecision(p) << t;
    return x.str();
  }

  template<class T>
  string fmt_scientific(T const &t, int w, int p) {
    std::ostringstream x;
    x << std::scientific << std::setw(w) << std::setprecision(p) << t;
    return x.str();
  }


  STRUTIL_EXTERN string atostr(char const *a);
  STRUTIL_EXTERN string flx_asprintf(char const *fmt,...);

  STRUTIL_EXTERN string flxid_to_cid(string const&);
  STRUTIL_EXTERN string filename_to_modulename (string const&);
  STRUTIL_EXTERN size_t string_hash(string const &s);
  STRUTIL_EXTERN char *flx_strdup(char const *);
  STRUTIL_EXTERN char *flx_cstr(::std::basic_string<char> const&);

}}}

#endif
//[flx_strutil.cpp]

#include <stdio.h>
#include <cstdint>
#include <cstring>

#include "flx_strutil.hpp"

namespace flx { namespace rtl { namespace strutil {

  char *flx_strdup(char const *p) {
    if (p==0) return NULL;
    auto n = ::std::strlen (p);
    auto q = (char*) ::std::malloc(n+1);
    strcpy (q,p);
    return q;
  }

  char *flx_cstr(::std::basic_string<char> const& s) {
    auto n = s.size();
    auto q = (char*) ::std::malloc(n+1);
    auto p = s.c_str();
    ::std::memcpy(q,p,n);
    q[n] = 0;
    return q;
  }

  string atostr(char const *a) {
    if(a) return a;
    else return "";
  }

  size_t string_hash(string const &s)
  {
    size_t hash = 5381;
    int c;
    char const *str = s.c_str();
    while (c = *str++)
        hash = (hash * 33 + c) % (size_t)1073741823ll; /* hash * 33 + c */
    return hash;
  }

  string flxid_to_cid (string const &s)
  {
    string out = "";
    int n = s.size();
    // leading digit
    if (n > 1 && s[0] >= '0' && s[0] <= '9') out += "_";
    for (int i = 0; i < n; ++i)
    {
      char ch = s[i];
      /* from http://www.w3.org/TR/html4/sgml/entities.html */
      switch (ch)
      {
        case ' ': out += "__sp_"; break;
        case '!': out += "__excl_"; break;
        case '"': out += "__quot_"; break;
        case '#': out += "__num_"; break;
        case '$': out += "__dollar_"; break;
        case '%': out += "__percnt_"; break;
        case '&': out += "__amp_"; break;
        case '\'':  out +=  "__apos_"; break;
        case '(': out += "__lpar_"; break;
        case ')': out += "__rpar_"; break;
        case '*': out += "__ast_"; break;
        case '+': out += "__plus_"; break;
        case ',': out += "__comma_"; break;
        case '-': out += "__hyphen_"; break;
        case '.': out += "__period_"; break;
        case '/': out += "__sol_"; break;
        case ':': out += "__colon_"; break;
        case ';': out += "__semi_"; break;
        case '<': out += "__lt_"; break;
        case '=': out += "__equals_"; break;
        case '>': out += "__gt_"; break;
        case '?': out += "__quest_"; break;
        case '@': out += "__commat_"; break;
        case '[': out += "__lsqb_"; break;
        case '\\': out += "__bsol_"; break;
        case ']': out += "__rsqb_"; break;
        case '^': out += "__caret_"; break;
        case '`': out += "__grave_"; break;
        case '{': out += "__lcub_"; break;
        case '|': out += "__verbar_"; break;
        case '}': out += "__rcub_"; break;
        case '~': out += "__tilde_"; break;
        default: out += string (1,ch);
      }
   }
   if (out.size() > 40)
     return out.substr(0,4) + flx_asprintf("_hash_%zu",string_hash(out));
   else
     return out;
  }

  string chop_extension (string const &s)
  {
     int n = s.size();
     for(int i = n - 1; i >= 0; --i)
     {
       if (s[i] == '/') return s;
       if (s[i] == '\\') return s;
       if (s[i] == '.') return s.substr(0,i);
     }
     return s;
  }

  string basename (string const &s)
  {
     int n = s.size();
     for(int i = n - 1; i >= 0; --i)
     {
       if (s[i] == '/') return s.substr (i+1,n-i);
       if (s[i] == '\\') return s.substr (i+1,n-i);
     }
     return s;
  }
  string filename_to_modulename (string const &s)
  {
     string a = basename (s);
     a = chop_extension (a);
     a = flxid_to_cid (a);
     return a;
  }

#ifdef FLX_HAVE_VSNPRINTF
  string flx_asprintf(char const *fmt,...){
    va_list ap;
    va_start(ap,fmt);
    //printf("vsnprintf TRIAL\n");
    int n = vsnprintf(NULL,0,fmt,ap);
    //printf("vsnprintf size=%d\n",n);
    va_end(ap);
    char *res = new char[n + 1];
    va_start(ap,fmt);
    vsnprintf(res,n+1,fmt,ap);
    va_end(ap);
    string s = string(res);
    delete [] res;
    return s;
  }
#else
  // THIS IS UNSAFE .. but Windows sucks.
  // It documents vsnprintf .. but doesn't provide it
  string flx_asprintf(char const *fmt,...){
    //printf("vsnprintf EMULATION!\n");
    va_list ap;
    int n = 10000; // hack, WILL crash if not enough
    char *res = new char[n+1];
    va_start(ap,fmt);
    vsprintf(res,fmt,ap);
    va_end(ap);
    string s = string(res);
    delete [] res;
    return s;
  }
#endif

}}}
//[flx_strutil_config.hpp]
#ifndef __FLX_STRUTIL_CONFIG_H__
#define __FLX_STRUTIL_CONFIG_H__
#include "flx_rtl_config.hpp"
#ifdef BUILD_STRUTIL
#define STRUTIL_EXTERN FLX_EXPORT
#else
#define STRUTIL_EXTERN FLX_IMPORT
#endif
#endif
//[unix_flx_strutil.fpc]
Name: flx_strutil
Description: String utilities
provides_dlib: -lflx_strutil_dynamic
provides_slib: -lflx_strutil_static
includes: '"flx_strutil.hpp"'
macros: BUILD_STRUTIL
library: flx_strutil
srcdir: src/strutil
src: .*\.cpp
//[win_flx_strutil.fpc]
Name: flx_strutil
Description: String utilities
provides_dlib: /DEFAULTLIB:flx_strutil_dynamic
provides_slib: /DEFAULTLIB:flx_strutil_static
includes: '"flx_strutil.hpp"'
macros: BUILD_STRUTIL
library: flx_strutil
srcdir: src/strutil
src: .*\.cpp

UTF codec.

//[flx_i18n.hpp]

#ifndef __FLX_I18N_H__
#define __FLX_I18N_H__
#include <string>
#include "flx_strutil_config.hpp"

namespace flx { namespace rtl { namespace i18n {
   STRUTIL_EXTERN std::string utf8(unsigned long);
}}}
#endif
//[flx_i18n.cpp]

#include "flx_i18n.hpp"
namespace flx { namespace rtl { namespace i18n {
  std::string utf8(unsigned long i)
  {
    char s[7];
    if (i < 0x80UL )
    {
      s[0]= i;
      s[1]= 0;
    }
    else if (i < 0x800UL )
    {
      s[0]=0xC0u | (i >> 6ul)  & 0x1Fu;
      s[1]=0x80u | i           & 0x3Fu;
      s[2]=0;
    }
    else if (i < 0x10000UL )
    {
      s[0]=0xE0u | (i >> 12ul) & 0xFu;
      s[1]=0x80u | (i >> 6ul)  & 0x3Fu;
      s[2]=0x80u | i           & 0x3F;
      s[3]=0;
    }
    else if (i < 0x200000UL )
    {
      s[0]=0xF0u | (i >> 18ul) & 0x7u;
      s[1]=0x80u | (i >> 12ul) & 0x3Fu;
      s[2]=0x80u | (i >> 6ul)  & 0x3Fu;
      s[3]=0x80u | i           & 0x3F;
      s[4]=0;
    }
    else if (i < 0x4000000UL )
    {
      s[0]=0xF8u | (i >> 24ul) & 0x3u;
      s[1]=0x80u | (i >> 18ul) & 0x3Fu;
      s[2]=0x80u | (i >> 12ul) & 0x3Fu;
      s[3]=0x80u | (i >> 6ul)  & 0x3Fu;
      s[4]=0x80u | i           & 0x3Fu;
      s[5]=0;
    }
    else
    {
      s[0]=0xFCu | (i >> 30ul) & 0x1u;
      s[1]=0x80u | (i >> 24ul) & 0x3Fu;
      s[2]=0x80u | (i >> 18ul) & 0x3Fu;
      s[3]=0x80u | (i >> 12ul) & 0x3Fu;
      s[4]=0x80u | (i >> 6ul)  & 0x3Fu;
      s[5]=0x80u | i           & 0x3Fu;
      s[6]=0;
    }
    return s;
  }
}}}

Config database entry

//[flx_i18n.fpc]
Name: flx_i18n
Description: Internationalisation support, Unicode, utf8
Requires: flx_strutil
includes: '"flx_i18n.hpp"'
#[flx_strutil.py]
import fbuild
from fbuild.path import Path
from fbuild.record import Record
from fbuild.builders.file import copy

import buildsystem

# ------------------------------------------------------------------------------

def build_runtime(phase):
    print('[fbuild] [rtl] build strutil')
    path = Path(phase.ctx.buildroot/'share'/'src'/'strutil')
    srcs = [f for f in Path.glob(path / '*.cpp')]
    includes = [phase.ctx.buildroot / 'host/lib/rtl', phase.ctx.buildroot / 'share/lib/rtl']
    macros = ['BUILD_STRUTIL']

    dst = 'host/lib/rtl/flx_strutil'
    return Record(
        static=buildsystem.build_cxx_static_lib(phase, dst, srcs,
            includes=includes,
            macros=macros),
        shared=buildsystem.build_cxx_shared_lib(phase, dst, srcs,
            includes=includes,
            macros=macros))