~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to debian/grub-extras/lua/lstrlib.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $
 
3
** Standard library for string operations and pattern-matching
 
4
** See Copyright Notice in lua.h
 
5
*/
 
6
 
 
7
#if 0
 
8
#include <ctype.h>
 
9
#include <stddef.h>
 
10
#include <stdio.h>
 
11
#include <stdlib.h>
 
12
#include <string.h>
 
13
#endif
 
14
 
 
15
#define lstrlib_c
 
16
#define LUA_LIB
 
17
 
 
18
#include "lua.h"
 
19
 
 
20
#include "lauxlib.h"
 
21
#include "lualib.h"
 
22
 
 
23
 
 
24
/* macro to `unsign' a character */
 
25
#define uchar(c)        ((unsigned char)(c))
 
26
 
 
27
 
 
28
 
 
29
static int str_len (lua_State *L) {
 
30
  size_t l;
 
31
  luaL_checklstring(L, 1, &l);
 
32
  lua_pushinteger(L, l);
 
33
  return 1;
 
34
}
 
35
 
 
36
 
 
37
static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) {
 
38
  /* relative string position: negative means back from end */
 
39
  if (pos < 0) pos += (ptrdiff_t)len + 1;
 
40
  return (pos >= 0) ? pos : 0;
 
41
}
 
42
 
 
43
 
 
44
static int str_sub (lua_State *L) {
 
45
  size_t l;
 
46
  const char *s = luaL_checklstring(L, 1, &l);
 
47
  ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l);
 
48
  ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l);
 
49
  if (start < 1) start = 1;
 
50
  if (end > (ptrdiff_t)l) end = (ptrdiff_t)l;
 
51
  if (start <= end)
 
52
    lua_pushlstring(L, s+start-1, end-start+1);
 
53
  else lua_pushliteral(L, "");
 
54
  return 1;
 
55
}
 
56
 
 
57
 
 
58
static int str_reverse (lua_State *L) {
 
59
  size_t l;
 
60
  luaL_Buffer b;
 
61
  const char *s = luaL_checklstring(L, 1, &l);
 
62
  luaL_buffinit(L, &b);
 
63
  while (l--) luaL_addchar(&b, s[l]);
 
64
  luaL_pushresult(&b);
 
65
  return 1;
 
66
}
 
67
 
 
68
 
 
69
static int str_lower (lua_State *L) {
 
70
  size_t l;
 
71
  size_t i;
 
72
  luaL_Buffer b;
 
73
  const char *s = luaL_checklstring(L, 1, &l);
 
74
  luaL_buffinit(L, &b);
 
75
  for (i=0; i<l; i++)
 
76
    luaL_addchar(&b, tolower(uchar(s[i])));
 
77
  luaL_pushresult(&b);
 
78
  return 1;
 
79
}
 
80
 
 
81
 
 
82
static int str_upper (lua_State *L) {
 
83
  size_t l;
 
84
  size_t i;
 
85
  luaL_Buffer b;
 
86
  const char *s = luaL_checklstring(L, 1, &l);
 
87
  luaL_buffinit(L, &b);
 
88
  for (i=0; i<l; i++)
 
89
    luaL_addchar(&b, toupper(uchar(s[i])));
 
90
  luaL_pushresult(&b);
 
91
  return 1;
 
92
}
 
93
 
 
94
static int str_rep (lua_State *L) {
 
95
  size_t l;
 
96
  luaL_Buffer b;
 
97
  const char *s = luaL_checklstring(L, 1, &l);
 
98
  int n = luaL_checkint(L, 2);
 
99
  luaL_buffinit(L, &b);
 
100
  while (n-- > 0)
 
101
    luaL_addlstring(&b, s, l);
 
102
  luaL_pushresult(&b);
 
103
  return 1;
 
104
}
 
105
 
 
106
 
 
107
static int str_byte (lua_State *L) {
 
108
  size_t l;
 
109
  const char *s = luaL_checklstring(L, 1, &l);
 
110
  ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l);
 
111
  ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l);
 
112
  int n, i;
 
113
  if (posi <= 0) posi = 1;
 
114
  if ((size_t)pose > l) pose = l;
 
115
  if (posi > pose) return 0;  /* empty interval; return no values */
 
116
  n = (int)(pose -  posi + 1);
 
117
  if (posi + n <= pose)  /* overflow? */
 
118
    luaL_error(L, "string slice too long");
 
119
  luaL_checkstack(L, n, "string slice too long");
 
120
  for (i=0; i<n; i++)
 
121
    lua_pushinteger(L, uchar(s[posi+i-1]));
 
122
  return n;
 
123
}
 
124
 
 
125
 
 
126
static int str_char (lua_State *L) {
 
127
  int n = lua_gettop(L);  /* number of arguments */
 
128
  int i;
 
129
  luaL_Buffer b;
 
130
  luaL_buffinit(L, &b);
 
131
  for (i=1; i<=n; i++) {
 
132
    int c = luaL_checkint(L, i);
 
133
    luaL_argcheck(L, uchar(c) == c, i, "invalid value");
 
134
    luaL_addchar(&b, uchar(c));
 
135
  }
 
136
  luaL_pushresult(&b);
 
137
  return 1;
 
138
}
 
139
 
 
140
 
 
141
static int writer (lua_State *L, const void* b, size_t size, void* B) {
 
142
  (void)L;
 
143
  luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
 
144
  return 0;
 
145
}
 
146
 
 
147
 
 
148
static int str_dump (lua_State *L) {
 
149
  luaL_Buffer b;
 
150
  luaL_checktype(L, 1, LUA_TFUNCTION);
 
151
  lua_settop(L, 1);
 
152
  luaL_buffinit(L,&b);
 
153
  if (lua_dump(L, writer, &b) != 0)
 
154
    luaL_error(L, "unable to dump given function");
 
155
  luaL_pushresult(&b);
 
156
  return 1;
 
157
}
 
158
 
 
159
 
 
160
 
 
161
/*
 
162
** {======================================================
 
163
** PATTERN MATCHING
 
164
** =======================================================
 
165
*/
 
166
 
 
167
 
 
168
#define CAP_UNFINISHED  (-1)
 
169
#define CAP_POSITION    (-2)
 
170
 
 
171
typedef struct MatchState {
 
172
  const char *src_init;  /* init of source string */
 
173
  const char *src_end;  /* end (`\0') of source string */
 
174
  lua_State *L;
 
175
  int level;  /* total number of captures (finished or unfinished) */
 
176
  struct {
 
177
    const char *init;
 
178
    ptrdiff_t len;
 
179
  } capture[LUA_MAXCAPTURES];
 
180
} MatchState;
 
181
 
 
182
 
 
183
#define L_ESC           '%'
 
184
#define SPECIALS        "^$*+?.([%-"
 
185
 
 
186
 
 
187
static int check_capture (MatchState *ms, int l) {
 
188
  l -= '1';
 
189
  if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
 
190
    return luaL_error(ms->L, "invalid capture index");
 
191
  return l;
 
192
}
 
193
 
 
194
 
 
195
static int capture_to_close (MatchState *ms) {
 
196
  int level = ms->level;
 
197
  for (level--; level>=0; level--)
 
198
    if (ms->capture[level].len == CAP_UNFINISHED) return level;
 
199
  return luaL_error(ms->L, "invalid pattern capture");
 
200
}
 
201
 
 
202
 
 
203
static const char *classend (MatchState *ms, const char *p) {
 
204
  switch (*p++) {
 
205
    case L_ESC: {
 
206
      if (*p == '\0')
 
207
        luaL_error(ms->L, "malformed pattern (ends with " LUA_QL("%%") ")");
 
208
      return p+1;
 
209
    }
 
210
    case '[': {
 
211
      if (*p == '^') p++;
 
212
      do {  /* look for a `]' */
 
213
        if (*p == '\0')
 
214
          luaL_error(ms->L, "malformed pattern (missing " LUA_QL("]") ")");
 
215
        if (*(p++) == L_ESC && *p != '\0')
 
216
          p++;  /* skip escapes (e.g. `%]') */
 
217
      } while (*p != ']');
 
218
      return p+1;
 
219
    }
 
220
    default: {
 
221
      return p;
 
222
    }
 
223
  }
 
224
}
 
225
 
 
226
 
 
227
static int match_class (int c, int cl) {
 
228
  int res;
 
229
  switch (tolower(cl)) {
 
230
    case 'a' : res = isalpha(c); break;
 
231
    case 'c' : res = iscntrl(c); break;
 
232
    case 'd' : res = isdigit(c); break;
 
233
    case 'l' : res = islower(c); break;
 
234
    case 'p' : res = ispunct(c); break;
 
235
    case 's' : res = isspace(c); break;
 
236
    case 'u' : res = isupper(c); break;
 
237
    case 'w' : res = isalnum(c); break;
 
238
    case 'x' : res = isxdigit(c); break;
 
239
    case 'z' : res = (c == 0); break;
 
240
    default: return (cl == c);
 
241
  }
 
242
  return (islower(cl) ? res : !res);
 
243
}
 
244
 
 
245
 
 
246
static int matchbracketclass (int c, const char *p, const char *ec) {
 
247
  int sig = 1;
 
248
  if (*(p+1) == '^') {
 
249
    sig = 0;
 
250
    p++;  /* skip the `^' */
 
251
  }
 
252
  while (++p < ec) {
 
253
    if (*p == L_ESC) {
 
254
      p++;
 
255
      if (match_class(c, uchar(*p)))
 
256
        return sig;
 
257
    }
 
258
    else if ((*(p+1) == '-') && (p+2 < ec)) {
 
259
      p+=2;
 
260
      if (uchar(*(p-2)) <= c && c <= uchar(*p))
 
261
        return sig;
 
262
    }
 
263
    else if (uchar(*p) == c) return sig;
 
264
  }
 
265
  return !sig;
 
266
}
 
267
 
 
268
 
 
269
static int singlematch (int c, const char *p, const char *ep) {
 
270
  switch (*p) {
 
271
    case '.': return 1;  /* matches any char */
 
272
    case L_ESC: return match_class(c, uchar(*(p+1)));
 
273
    case '[': return matchbracketclass(c, p, ep-1);
 
274
    default:  return (uchar(*p) == c);
 
275
  }
 
276
}
 
277
 
 
278
 
 
279
static const char *match (MatchState *ms, const char *s, const char *p);
 
280
 
 
281
 
 
282
static const char *matchbalance (MatchState *ms, const char *s,
 
283
                                   const char *p) {
 
284
  if (*p == 0 || *(p+1) == 0)
 
285
    luaL_error(ms->L, "unbalanced pattern");
 
286
  if (*s != *p) return NULL;
 
287
  else {
 
288
    int b = *p;
 
289
    int e = *(p+1);
 
290
    int cont = 1;
 
291
    while (++s < ms->src_end) {
 
292
      if (*s == e) {
 
293
        if (--cont == 0) return s+1;
 
294
      }
 
295
      else if (*s == b) cont++;
 
296
    }
 
297
  }
 
298
  return NULL;  /* string ends out of balance */
 
299
}
 
300
 
 
301
 
 
302
static const char *max_expand (MatchState *ms, const char *s,
 
303
                                 const char *p, const char *ep) {
 
304
  ptrdiff_t i = 0;  /* counts maximum expand for item */
 
305
  while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
 
306
    i++;
 
307
  /* keeps trying to match with the maximum repetitions */
 
308
  while (i>=0) {
 
309
    const char *res = match(ms, (s+i), ep+1);
 
310
    if (res) return res;
 
311
    i--;  /* else didn't match; reduce 1 repetition to try again */
 
312
  }
 
313
  return NULL;
 
314
}
 
315
 
 
316
 
 
317
static const char *min_expand (MatchState *ms, const char *s,
 
318
                                 const char *p, const char *ep) {
 
319
  for (;;) {
 
320
    const char *res = match(ms, s, ep+1);
 
321
    if (res != NULL)
 
322
      return res;
 
323
    else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
 
324
      s++;  /* try with one more repetition */
 
325
    else return NULL;
 
326
  }
 
327
}
 
328
 
 
329
 
 
330
static const char *start_capture (MatchState *ms, const char *s,
 
331
                                    const char *p, int what) {
 
332
  const char *res;
 
333
  int level = ms->level;
 
334
  if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures");
 
335
  ms->capture[level].init = s;
 
336
  ms->capture[level].len = what;
 
337
  ms->level = level+1;
 
338
  if ((res=match(ms, s, p)) == NULL)  /* match failed? */
 
339
    ms->level--;  /* undo capture */
 
340
  return res;
 
341
}
 
342
 
 
343
 
 
344
static const char *end_capture (MatchState *ms, const char *s,
 
345
                                  const char *p) {
 
346
  int l = capture_to_close(ms);
 
347
  const char *res;
 
348
  ms->capture[l].len = s - ms->capture[l].init;  /* close capture */
 
349
  if ((res = match(ms, s, p)) == NULL)  /* match failed? */
 
350
    ms->capture[l].len = CAP_UNFINISHED;  /* undo capture */
 
351
  return res;
 
352
}
 
353
 
 
354
 
 
355
static const char *match_capture (MatchState *ms, const char *s, int l) {
 
356
  size_t len;
 
357
  l = check_capture(ms, l);
 
358
  len = ms->capture[l].len;
 
359
  if ((size_t)(ms->src_end-s) >= len &&
 
360
      memcmp(ms->capture[l].init, s, len) == 0)
 
361
    return s+len;
 
362
  else return NULL;
 
363
}
 
364
 
 
365
 
 
366
static const char *match (MatchState *ms, const char *s, const char *p) {
 
367
  init: /* using goto's to optimize tail recursion */
 
368
  switch (*p) {
 
369
    case '(': {  /* start capture */
 
370
      if (*(p+1) == ')')  /* position capture? */
 
371
        return start_capture(ms, s, p+2, CAP_POSITION);
 
372
      else
 
373
        return start_capture(ms, s, p+1, CAP_UNFINISHED);
 
374
    }
 
375
    case ')': {  /* end capture */
 
376
      return end_capture(ms, s, p+1);
 
377
    }
 
378
    case L_ESC: {
 
379
      switch (*(p+1)) {
 
380
        case 'b': {  /* balanced string? */
 
381
          s = matchbalance(ms, s, p+2);
 
382
          if (s == NULL) return NULL;
 
383
          p+=4; goto init;  /* else return match(ms, s, p+4); */
 
384
        }
 
385
        case 'f': {  /* frontier? */
 
386
          const char *ep; char previous;
 
387
          p += 2;
 
388
          if (*p != '[')
 
389
            luaL_error(ms->L, "missing " LUA_QL("[") " after "
 
390
                               LUA_QL("%%f") " in pattern");
 
391
          ep = classend(ms, p);  /* points to what is next */
 
392
          previous = (s == ms->src_init) ? '\0' : *(s-1);
 
393
          if (matchbracketclass(uchar(previous), p, ep-1) ||
 
394
             !matchbracketclass(uchar(*s), p, ep-1)) return NULL;
 
395
          p=ep; goto init;  /* else return match(ms, s, ep); */
 
396
        }
 
397
        default: {
 
398
          if (isdigit(uchar(*(p+1)))) {  /* capture results (%0-%9)? */
 
399
            s = match_capture(ms, s, uchar(*(p+1)));
 
400
            if (s == NULL) return NULL;
 
401
            p+=2; goto init;  /* else return match(ms, s, p+2) */
 
402
          }
 
403
          goto dflt;  /* case default */
 
404
        }
 
405
      }
 
406
    }
 
407
    case '\0': {  /* end of pattern */
 
408
      return s;  /* match succeeded */
 
409
    }
 
410
    case '$': {
 
411
      if (*(p+1) == '\0')  /* is the `$' the last char in pattern? */
 
412
        return (s == ms->src_end) ? s : NULL;  /* check end of string */
 
413
      else goto dflt;
 
414
    }
 
415
    default: dflt: {  /* it is a pattern item */
 
416
      const char *ep = classend(ms, p);  /* points to what is next */
 
417
      int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
 
418
      switch (*ep) {
 
419
        case '?': {  /* optional */
 
420
          const char *res;
 
421
          if (m && ((res=match(ms, s+1, ep+1)) != NULL))
 
422
            return res;
 
423
          p=ep+1; goto init;  /* else return match(ms, s, ep+1); */
 
424
        }
 
425
        case '*': {  /* 0 or more repetitions */
 
426
          return max_expand(ms, s, p, ep);
 
427
        }
 
428
        case '+': {  /* 1 or more repetitions */
 
429
          return (m ? max_expand(ms, s+1, p, ep) : NULL);
 
430
        }
 
431
        case '-': {  /* 0 or more repetitions (minimum) */
 
432
          return min_expand(ms, s, p, ep);
 
433
        }
 
434
        default: {
 
435
          if (!m) return NULL;
 
436
          s++; p=ep; goto init;  /* else return match(ms, s+1, ep); */
 
437
        }
 
438
      }
 
439
    }
 
440
  }
 
441
}
 
442
 
 
443
 
 
444
 
 
445
static const char *lmemfind (const char *s1, size_t l1,
 
446
                               const char *s2, size_t l2) {
 
447
  if (l2 == 0) return s1;  /* empty strings are everywhere */
 
448
  else if (l2 > l1) return NULL;  /* avoids a negative `l1' */
 
449
  else {
 
450
    const char *init;  /* to search for a `*s2' inside `s1' */
 
451
    l2--;  /* 1st char will be checked by `memchr' */
 
452
    l1 = l1-l2;  /* `s2' cannot be found after that */
 
453
    while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
 
454
      init++;   /* 1st char is already checked */
 
455
      if (memcmp(init, s2+1, l2) == 0)
 
456
        return init-1;
 
457
      else {  /* correct `l1' and `s1' to try again */
 
458
        l1 -= init-s1;
 
459
        s1 = init;
 
460
      }
 
461
    }
 
462
    return NULL;  /* not found */
 
463
  }
 
464
}
 
465
 
 
466
 
 
467
static void push_onecapture (MatchState *ms, int i, const char *s,
 
468
                                                    const char *e) {
 
469
  if (i >= ms->level) {
 
470
    if (i == 0)  /* ms->level == 0, too */
 
471
      lua_pushlstring(ms->L, s, e - s);  /* add whole match */
 
472
    else
 
473
      luaL_error(ms->L, "invalid capture index");
 
474
  }
 
475
  else {
 
476
    ptrdiff_t l = ms->capture[i].len;
 
477
    if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
 
478
    if (l == CAP_POSITION)
 
479
      lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
 
480
    else
 
481
      lua_pushlstring(ms->L, ms->capture[i].init, l);
 
482
  }
 
483
}
 
484
 
 
485
 
 
486
static int push_captures (MatchState *ms, const char *s, const char *e) {
 
487
  int i;
 
488
  int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
 
489
  luaL_checkstack(ms->L, nlevels, "too many captures");
 
490
  for (i = 0; i < nlevels; i++)
 
491
    push_onecapture(ms, i, s, e);
 
492
  return nlevels;  /* number of strings pushed */
 
493
}
 
494
 
 
495
 
 
496
static int str_find_aux (lua_State *L, int find) {
 
497
  size_t l1, l2;
 
498
  const char *s = luaL_checklstring(L, 1, &l1);
 
499
  const char *p = luaL_checklstring(L, 2, &l2);
 
500
  ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1;
 
501
  if (init < 0) init = 0;
 
502
  else if ((size_t)(init) > l1) init = (ptrdiff_t)l1;
 
503
  if (find && (lua_toboolean(L, 4) ||  /* explicit request? */
 
504
      strpbrk(p, SPECIALS) == NULL)) {  /* or no special characters? */
 
505
    /* do a plain search */
 
506
    const char *s2 = lmemfind(s+init, l1-init, p, l2);
 
507
    if (s2) {
 
508
      lua_pushinteger(L, s2-s+1);
 
509
      lua_pushinteger(L, s2-s+l2);
 
510
      return 2;
 
511
    }
 
512
  }
 
513
  else {
 
514
    MatchState ms;
 
515
    int anchor = (*p == '^') ? (p++, 1) : 0;
 
516
    const char *s1=s+init;
 
517
    ms.L = L;
 
518
    ms.src_init = s;
 
519
    ms.src_end = s+l1;
 
520
    do {
 
521
      const char *res;
 
522
      ms.level = 0;
 
523
      if ((res=match(&ms, s1, p)) != NULL) {
 
524
        if (find) {
 
525
          lua_pushinteger(L, s1-s+1);  /* start */
 
526
          lua_pushinteger(L, res-s);   /* end */
 
527
          return push_captures(&ms, NULL, 0) + 2;
 
528
        }
 
529
        else
 
530
          return push_captures(&ms, s1, res);
 
531
      }
 
532
    } while (s1++ < ms.src_end && !anchor);
 
533
  }
 
534
  lua_pushnil(L);  /* not found */
 
535
  return 1;
 
536
}
 
537
 
 
538
 
 
539
static int str_find (lua_State *L) {
 
540
  return str_find_aux(L, 1);
 
541
}
 
542
 
 
543
 
 
544
static int str_match (lua_State *L) {
 
545
  return str_find_aux(L, 0);
 
546
}
 
547
 
 
548
 
 
549
static int gmatch_aux (lua_State *L) {
 
550
  MatchState ms;
 
551
  size_t ls;
 
552
  const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
 
553
  const char *p = lua_tostring(L, lua_upvalueindex(2));
 
554
  const char *src;
 
555
  ms.L = L;
 
556
  ms.src_init = s;
 
557
  ms.src_end = s+ls;
 
558
  for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
 
559
       src <= ms.src_end;
 
560
       src++) {
 
561
    const char *e;
 
562
    ms.level = 0;
 
563
    if ((e = match(&ms, src, p)) != NULL) {
 
564
      lua_Integer newstart = e-s;
 
565
      if (e == src) newstart++;  /* empty match? go at least one position */
 
566
      lua_pushinteger(L, newstart);
 
567
      lua_replace(L, lua_upvalueindex(3));
 
568
      return push_captures(&ms, src, e);
 
569
    }
 
570
  }
 
571
  return 0;  /* not found */
 
572
}
 
573
 
 
574
 
 
575
static int gmatch (lua_State *L) {
 
576
  luaL_checkstring(L, 1);
 
577
  luaL_checkstring(L, 2);
 
578
  lua_settop(L, 2);
 
579
  lua_pushinteger(L, 0);
 
580
  lua_pushcclosure(L, gmatch_aux, 3);
 
581
  return 1;
 
582
}
 
583
 
 
584
 
 
585
static int gfind_nodef (lua_State *L) {
 
586
  return luaL_error(L, LUA_QL("string.gfind") " was renamed to "
 
587
                       LUA_QL("string.gmatch"));
 
588
}
 
589
 
 
590
 
 
591
static void add_s (MatchState *ms, luaL_Buffer *b, const char *s,
 
592
                                                   const char *e) {
 
593
  size_t l, i;
 
594
  const char *news = lua_tolstring(ms->L, 3, &l);
 
595
  for (i = 0; i < l; i++) {
 
596
    if (news[i] != L_ESC)
 
597
      luaL_addchar(b, news[i]);
 
598
    else {
 
599
      i++;  /* skip ESC */
 
600
      if (!isdigit(uchar(news[i])))
 
601
        luaL_addchar(b, news[i]);
 
602
      else if (news[i] == '0')
 
603
          luaL_addlstring(b, s, e - s);
 
604
      else {
 
605
        push_onecapture(ms, news[i] - '1', s, e);
 
606
        luaL_addvalue(b);  /* add capture to accumulated result */
 
607
      }
 
608
    }
 
609
  }
 
610
}
 
611
 
 
612
 
 
613
static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
 
614
                                                       const char *e) {
 
615
  lua_State *L = ms->L;
 
616
  switch (lua_type(L, 3)) {
 
617
    case LUA_TNUMBER:
 
618
    case LUA_TSTRING: {
 
619
      add_s(ms, b, s, e);
 
620
      return;
 
621
    }
 
622
    case LUA_TFUNCTION: {
 
623
      int n;
 
624
      lua_pushvalue(L, 3);
 
625
      n = push_captures(ms, s, e);
 
626
      lua_call(L, n, 1);
 
627
      break;
 
628
    }
 
629
    case LUA_TTABLE: {
 
630
      push_onecapture(ms, 0, s, e);
 
631
      lua_gettable(L, 3);
 
632
      break;
 
633
    }
 
634
  }
 
635
  if (!lua_toboolean(L, -1)) {  /* nil or false? */
 
636
    lua_pop(L, 1);
 
637
    lua_pushlstring(L, s, e - s);  /* keep original text */
 
638
  }
 
639
  else if (!lua_isstring(L, -1))
 
640
    luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1));
 
641
  luaL_addvalue(b);  /* add result to accumulator */
 
642
}
 
643
 
 
644
 
 
645
static int str_gsub (lua_State *L) {
 
646
  size_t srcl;
 
647
  const char *src = luaL_checklstring(L, 1, &srcl);
 
648
  const char *p = luaL_checkstring(L, 2);
 
649
  int  tr = lua_type(L, 3);
 
650
  int max_s = luaL_optint(L, 4, srcl+1);
 
651
  int anchor = (*p == '^') ? (p++, 1) : 0;
 
652
  int n = 0;
 
653
  MatchState ms;
 
654
  luaL_Buffer b;
 
655
  luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
 
656
                   tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
 
657
                      "string/function/table expected");
 
658
  luaL_buffinit(L, &b);
 
659
  ms.L = L;
 
660
  ms.src_init = src;
 
661
  ms.src_end = src+srcl;
 
662
  while (n < max_s) {
 
663
    const char *e;
 
664
    ms.level = 0;
 
665
    e = match(&ms, src, p);
 
666
    if (e) {
 
667
      n++;
 
668
      add_value(&ms, &b, src, e);
 
669
    }
 
670
    if (e && e>src) /* non empty match? */
 
671
      src = e;  /* skip it */
 
672
    else if (src < ms.src_end)
 
673
      luaL_addchar(&b, *src++);
 
674
    else break;
 
675
    if (anchor) break;
 
676
  }
 
677
  luaL_addlstring(&b, src, ms.src_end-src);
 
678
  luaL_pushresult(&b);
 
679
  lua_pushinteger(L, n);  /* number of substitutions */
 
680
  return 2;
 
681
}
 
682
 
 
683
/* }====================================================== */
 
684
 
 
685
 
 
686
/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
 
687
#define MAX_ITEM        512
 
688
/* valid flags in a format specification */
 
689
#define FLAGS   "-+ #0"
 
690
/*
 
691
** maximum size of each format specification (such as '%-099.99d')
 
692
** (+10 accounts for %99.99x plus margin of error)
 
693
*/
 
694
#define MAX_FORMAT      (sizeof(FLAGS) + sizeof(LUA_INTFRMLEN) + 10)
 
695
 
 
696
 
 
697
static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
 
698
  size_t l;
 
699
  const char *s = luaL_checklstring(L, arg, &l);
 
700
  luaL_addchar(b, '"');
 
701
  while (l--) {
 
702
    switch (*s) {
 
703
      case '"': case '\\': case '\n': {
 
704
        luaL_addchar(b, '\\');
 
705
        luaL_addchar(b, *s);
 
706
        break;
 
707
      }
 
708
      case '\r': {
 
709
        luaL_addlstring(b, "\\r", 2);
 
710
        break;
 
711
      }
 
712
      case '\0': {
 
713
        luaL_addlstring(b, "\\000", 4);
 
714
        break;
 
715
      }
 
716
      default: {
 
717
        luaL_addchar(b, *s);
 
718
        break;
 
719
      }
 
720
    }
 
721
    s++;
 
722
  }
 
723
  luaL_addchar(b, '"');
 
724
}
 
725
 
 
726
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
 
727
  const char *p = strfrmt;
 
728
  while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++;  /* skip flags */
 
729
  if ((size_t)(p - strfrmt) >= sizeof(FLAGS))
 
730
    luaL_error(L, "invalid format (repeated flags)");
 
731
  if (isdigit(uchar(*p))) p++;  /* skip width */
 
732
  if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
 
733
  if (*p == '.') {
 
734
    p++;
 
735
    if (isdigit(uchar(*p))) p++;  /* skip precision */
 
736
    if (isdigit(uchar(*p))) p++;  /* (2 digits at most) */
 
737
  }
 
738
  if (isdigit(uchar(*p)))
 
739
    luaL_error(L, "invalid format (width or precision too long)");
 
740
  *(form++) = '%';
 
741
  strncpy(form, strfrmt, p - strfrmt + 1);
 
742
  form += p - strfrmt + 1;
 
743
  *form = '\0';
 
744
  return p;
 
745
}
 
746
 
 
747
 
 
748
static void addintlen (char *form) {
 
749
  size_t l = strlen(form);
 
750
  char spec = form[l - 1];
 
751
  strcpy(form + l - 1, LUA_INTFRMLEN);
 
752
  form[l + sizeof(LUA_INTFRMLEN) - 2] = spec;
 
753
  form[l + sizeof(LUA_INTFRMLEN) - 1] = '\0';
 
754
}
 
755
 
 
756
 
 
757
static int str_format (lua_State *L) {
 
758
  int arg = 1;
 
759
  size_t sfl;
 
760
  const char *strfrmt = luaL_checklstring(L, arg, &sfl);
 
761
  const char *strfrmt_end = strfrmt+sfl;
 
762
  luaL_Buffer b;
 
763
  luaL_buffinit(L, &b);
 
764
  while (strfrmt < strfrmt_end) {
 
765
    if (*strfrmt != L_ESC)
 
766
      luaL_addchar(&b, *strfrmt++);
 
767
    else if (*++strfrmt == L_ESC)
 
768
      luaL_addchar(&b, *strfrmt++);  /* %% */
 
769
    else { /* format item */
 
770
      char form[MAX_FORMAT];  /* to store the format (`%...') */
 
771
      char buff[MAX_ITEM];  /* to store the formatted item */
 
772
      arg++;
 
773
      strfrmt = scanformat(L, strfrmt, form);
 
774
      switch (*strfrmt++) {
 
775
        case 'c': {
 
776
          snprintf(buff, sizeof (buff), form, (int)luaL_checknumber(L, arg));
 
777
          break;
 
778
        }
 
779
        case 'd':  case 'i': {
 
780
          addintlen(form);
 
781
          snprintf(buff, sizeof (buff), form,
 
782
                   (LUA_INTFRM_T)luaL_checknumber(L, arg));
 
783
          break;
 
784
        }
 
785
        case 'o':  case 'u':  case 'x':  case 'X': {
 
786
          addintlen(form);
 
787
          snprintf(buff, sizeof (buff), form,
 
788
                  (unsigned LUA_INTFRM_T)luaL_checknumber(L, arg));
 
789
          break;
 
790
        }
 
791
        case 'e':  case 'E': case 'f':
 
792
        case 'g': case 'G': {
 
793
          snprintf(buff, sizeof (buff), form, (double)luaL_checknumber(L, arg));
 
794
          break;
 
795
        }
 
796
        case 'q': {
 
797
          addquoted(L, &b, arg);
 
798
          continue;  /* skip the 'addsize' at the end */
 
799
        }
 
800
        case 's': {
 
801
          size_t l;
 
802
          const char *s = luaL_checklstring(L, arg, &l);
 
803
          if (!strchr(form, '.') && l >= 100) {
 
804
            /* no precision and string is too long to be formatted;
 
805
               keep original string */
 
806
            lua_pushvalue(L, arg);
 
807
            luaL_addvalue(&b);
 
808
            continue;  /* skip the `addsize' at the end */
 
809
          }
 
810
          else {
 
811
            snprintf(buff, sizeof (buff), form, s);
 
812
            break;
 
813
          }
 
814
        }
 
815
        default: {  /* also treat cases `pnLlh' */
 
816
          return luaL_error(L, "invalid option " LUA_QL("%%%c") " to "
 
817
                               LUA_QL("format"), *(strfrmt - 1));
 
818
        }
 
819
      }
 
820
      luaL_addlstring(&b, buff, strlen(buff));
 
821
    }
 
822
  }
 
823
  luaL_pushresult(&b);
 
824
  return 1;
 
825
}
 
826
 
 
827
 
 
828
static const luaL_Reg strlib[] = {
 
829
  {"byte", str_byte},
 
830
  {"char", str_char},
 
831
  {"dump", str_dump},
 
832
  {"find", str_find},
 
833
  {"format", str_format},
 
834
  {"gfind", gfind_nodef},
 
835
  {"gmatch", gmatch},
 
836
  {"gsub", str_gsub},
 
837
  {"len", str_len},
 
838
  {"lower", str_lower},
 
839
  {"match", str_match},
 
840
  {"rep", str_rep},
 
841
  {"reverse", str_reverse},
 
842
  {"sub", str_sub},
 
843
  {"upper", str_upper},
 
844
  {NULL, NULL}
 
845
};
 
846
 
 
847
 
 
848
static void createmetatable (lua_State *L) {
 
849
  lua_createtable(L, 0, 1);  /* create metatable for strings */
 
850
  lua_pushliteral(L, "");  /* dummy string */
 
851
  lua_pushvalue(L, -2);
 
852
  lua_setmetatable(L, -2);  /* set string metatable */
 
853
  lua_pop(L, 1);  /* pop dummy string */
 
854
  lua_pushvalue(L, -2);  /* string library... */
 
855
  lua_setfield(L, -2, "__index");  /* ...is the __index metamethod */
 
856
  lua_pop(L, 1);  /* pop metatable */
 
857
}
 
858
 
 
859
 
 
860
/*
 
861
** Open string library
 
862
*/
 
863
LUALIB_API int luaopen_string (lua_State *L) {
 
864
  luaL_register(L, LUA_STRLIBNAME, strlib);
 
865
#if defined(LUA_COMPAT_GFIND)
 
866
  lua_getfield(L, -1, "gmatch");
 
867
  lua_setfield(L, -2, "gfind");
 
868
#endif
 
869
  createmetatable(L);
 
870
  return 1;
 
871
}
 
872