1/* -*- c -*-
2 * File: pstring.h
3 * Author: Igor Vlasenko <vlasenko@imath.kiev.ua>
4 * Created: Fri Jul  1 20:11:51 2005
5 *
6 * $Id$
7 */
8
9#include <stdio.h>
10#include <string.h>
11#include <ctype.h>
12#include "pbuffer.h"
13#include "pstring.h"
14
15static
16PSTRING
17lowercase_pstring (pbuffer* pBuffer ,PSTRING pstring) {
18  const size_t size=pstring.endnext-pstring.begin;
19  char* buf=pbuffer_resize(pBuffer, size+1);
20  char* inbuf=buf;
21  const char* i=pstring.begin;
22  PSTRING retval;
23  while (i<pstring.endnext) {
24    *inbuf++=tolower((unsigned char) *i++);
25  }
26  *inbuf=0;
27  retval.begin=buf;
28  retval.endnext=buf+size;
29  return retval;
30}
31
32/*
33static
34void
35lowercase_pstring_inplace (PSTRING pstring) {
36  char* i=pstring.begin;
37  while (i<pstring.endnext) {
38    *i=tolower(*i);
39    i++;
40  }
41}
42*/
43
44static
45PSTRING
46uppercase_pstring (pbuffer* pBuffer ,PSTRING pstring) {
47  const size_t size=pstring.endnext-pstring.begin;
48  char* buf=pbuffer_resize(pBuffer, size+1);
49  char* inbuf=buf;
50  const char* i=pstring.begin;
51  PSTRING retval;
52  while (i<pstring.endnext) {
53    *inbuf++=toupper((unsigned char) *i++);
54  }
55  *inbuf=0;
56  retval.begin=buf;
57  retval.endnext=buf+size;
58  return retval;
59}
60
61
62static
63int
64is_pstring_true (PSTRING s) {
65  const size_t len = s.endnext-s.begin;
66  if (s.begin == NULL || 0==len) return 0;
67  if (1==len) {
68    if (*(s.begin)=='0') return 0; else return 1;
69  } else if (3==len) {
70    if ('0'==*(s.begin) && '.'==*(s.begin+1) && '0'==*(s.begin+2)) return 0; else return 1;
71  } else return 1;
72}
73
74#define MAX_ESCAPE_SEQ sizeof("&quot;")
75static
76PSTRING
77htmlencode_pstring (pbuffer* StrBuffer, PSTRING pstring) {
78  char* buf=pbuffer_resize(StrBuffer, pstring.endnext-pstring.begin+1+MAX_ESCAPE_SEQ);
79  const char* curpos=pstring.begin;
80  size_t offset=0;
81  size_t buflen=pbuffer_size(StrBuffer);
82  PSTRING retval;
83  while (curpos<pstring.endnext) {
84    unsigned char curchar=*curpos++;
85    int bufdelta=1;
86    if (offset>=buflen-MAX_ESCAPE_SEQ) {
87      buf=pbuffer_resize(StrBuffer, 2*(offset+MAX_ESCAPE_SEQ));
88      buflen=pbuffer_size(StrBuffer);
89    }
90    switch (curchar) {
91      /* straight from the CGI.pm bible. (HTML::Template) */
92    case '&' : bufdelta=5; strncpy(buf+offset, "&amp;", bufdelta);break;
93    case '"' : bufdelta=6; strncpy(buf+offset, "&quot;",bufdelta);break;
94    case '>' : bufdelta=4; strncpy(buf+offset, "&gt;",  bufdelta);break;
95    case '<' : bufdelta=4; strncpy(buf+offset, "&lt;",  bufdelta);break;
96    case '\'': bufdelta=5; strncpy(buf+offset, "&#39;", bufdelta);break;
97    default: *(buf+offset)=curchar;
98    }
99    offset+=bufdelta;
100  }
101  retval.begin=buf;
102  retval.endnext=buf+offset;
103  return retval;
104}
105
106static
107PSTRING
108jsencode_pstring (pbuffer* StrBuffer, PSTRING pstring) {
109  char* buf=pbuffer_resize(StrBuffer, pstring.endnext-pstring.begin+1+MAX_ESCAPE_SEQ);
110  const char* curpos=pstring.begin;
111  size_t offset=0;
112  size_t buflen=pbuffer_size(StrBuffer);
113  PSTRING retval;
114  while (curpos<pstring.endnext) {
115    unsigned char curchar=*curpos++;
116    int bufdelta=1;
117    if (offset>=buflen-MAX_ESCAPE_SEQ) {
118      buf=pbuffer_resize(StrBuffer, 2*(offset+MAX_ESCAPE_SEQ));
119      buflen=pbuffer_size(StrBuffer);
120    }
121    switch (curchar) {
122    case '\\' : bufdelta=6; strncpy(buf+offset, "\\u005c", bufdelta);break;
123    case '"'  : bufdelta=6; strncpy(buf+offset, "\\u0022",bufdelta);break;
124    case '\'' : bufdelta=6; strncpy(buf+offset, "\\u0027",bufdelta);break;
125    case '\n' : bufdelta=6; strncpy(buf+offset, "\\u000a",bufdelta);break;
126    case '\r' : bufdelta=6; strncpy(buf+offset, "\\u000d",bufdelta);break;
127    case '>' : bufdelta=6; strncpy(buf+offset, "\\u003e;",  bufdelta);break;
128    case '<' : bufdelta=6; strncpy(buf+offset, "\\u003c;",  bufdelta);break;
129    case '&' : bufdelta=6; strncpy(buf+offset, "\\u0026;",  bufdelta);break;
130    case '=' : bufdelta=6; strncpy(buf+offset, "\\u003d;",  bufdelta);break;
131    case '-' : bufdelta=6; strncpy(buf+offset, "\\u002d;",  bufdelta);break;
132    case ';' : bufdelta=6; strncpy(buf+offset, "\\u003b;",  bufdelta);break;
133    case '+' : bufdelta=6; strncpy(buf+offset, "\\u002b;",  bufdelta);break;
134    default: *(buf+offset)=curchar;
135    }
136    offset+=bufdelta;
137  }
138  retval.begin=buf;
139  retval.endnext=buf+offset;
140  return retval;
141}
142
143static
144PSTRING
145urlencode_pstring (pbuffer* StrBuffer, PSTRING pstring) {
146  char* buf=pbuffer_resize(StrBuffer, pstring.endnext-pstring.begin+1+MAX_ESCAPE_SEQ);
147  const char* curpos=pstring.begin;
148  size_t offset=0;
149  size_t buflen=pbuffer_size(StrBuffer);
150  PSTRING retval;
151  while (curpos<pstring.endnext) {
152    unsigned char curchar=*curpos++;
153    int bufdelta=1;
154    if (offset>=buflen-MAX_ESCAPE_SEQ) {
155      buf=pbuffer_resize(StrBuffer, 2*(offset+MAX_ESCAPE_SEQ));
156      buflen=pbuffer_size(StrBuffer);
157    }
158    /*
159     * # do the translation (RFC 2396 ^uric)
160     * s!([^a-zA-Z0-9_.\-])!sprintf('%%%02X', $_)
161     */
162    if ((curchar>='a' && curchar<='z') ||
163	(curchar>='A' && curchar<='Z') ||
164	(curchar>='0' && curchar<='9') ||
165	curchar=='_' || curchar=='.' || curchar=='\\' || curchar=='-'
166	)
167      *(buf+offset)=curchar;
168    else {
169      bufdelta=3; sprintf(buf+offset,"%%%.2X",(int) curchar);
170    }
171    offset+=bufdelta;
172  }
173  retval.begin=buf;
174  retval.endnext=buf+offset;
175  return retval;
176}
177
178static
179PSTRING
180escape_pstring (pbuffer* strBuffer, PSTRING pstring, const int escapeopt) {
181  switch (escapeopt) {
182  case HTML_TEMPLATE_OPT_ESCAPE_HTML:
183    return htmlencode_pstring(strBuffer, pstring);
184  case HTML_TEMPLATE_OPT_ESCAPE_JS:
185    return jsencode_pstring(strBuffer, pstring);
186  case HTML_TEMPLATE_OPT_ESCAPE_URL:
187    return urlencode_pstring(strBuffer, pstring);
188  default : return pstring;
189  }
190}
191