mirror of https://github.com/tstack/lnav
[sqlite] Major improvements to the sqlite integration.
This is a checkpoint of the improvements to the sqlite integration. The data_parser stuff should be much better now and I've tried to improve other parts of the user experience as well.pull/69/head
parent
b04e6bfc78
commit
3128dc772c
@ -0,0 +1,161 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2013, Timothy Stack
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @file logfile_sub_source.hh
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "strnatcmp.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_ADDR_LEN 128
|
||||||
|
|
||||||
|
static int strncmp2(int a_len, const char *a_str,
|
||||||
|
int b_len, const char *b_str)
|
||||||
|
{
|
||||||
|
int retval = strncmp(a_str, b_str, std::min(a_len, b_len));
|
||||||
|
|
||||||
|
if (retval == 0) {
|
||||||
|
if (a_len < b_len) {
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int try_inet_pton(int p_len, const char *p, char *n)
|
||||||
|
{
|
||||||
|
static int family[] = { AF_INET6, AF_INET, AF_MAX };
|
||||||
|
|
||||||
|
char buf[MAX_ADDR_LEN];
|
||||||
|
int retval = AF_MAX;
|
||||||
|
|
||||||
|
strncpy(buf, p, p_len);
|
||||||
|
buf[p_len] = '\0';
|
||||||
|
for (int lpc = 0; family[lpc] != AF_MAX; lpc++) {
|
||||||
|
if (inet_pton(family[lpc], buf, n) == 1) {
|
||||||
|
retval = family[lpc];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int convert_v6_to_v4(int family, char *n)
|
||||||
|
{
|
||||||
|
struct in6_addr *ia = (struct in6_addr *)n;
|
||||||
|
|
||||||
|
if (family == AF_INET6 &&
|
||||||
|
(IN6_IS_ADDR_V4COMPAT(ia) ||
|
||||||
|
IN6_IS_ADDR_V4MAPPED(ia))) {
|
||||||
|
family = AF_INET;
|
||||||
|
memmove(n, n + 12, sizeof(struct in_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return family;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int ipaddress(void *ptr,
|
||||||
|
int a_len, const void *a_in,
|
||||||
|
int b_len, const void *b_in)
|
||||||
|
{
|
||||||
|
char a_addr[sizeof(struct in6_addr)], b_addr[sizeof(struct in6_addr)];
|
||||||
|
const char *a_str = (const char *)a_in, *b_str = (const char *)b_in;
|
||||||
|
int a_family, b_family, retval;
|
||||||
|
|
||||||
|
if (a_len > MAX_ADDR_LEN || b_len > MAX_ADDR_LEN) {
|
||||||
|
return strncmp2(a_len, a_str, b_len, b_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
a_family = try_inet_pton(a_len, a_str, a_addr);
|
||||||
|
b_family = try_inet_pton(b_len, b_str, b_addr);
|
||||||
|
|
||||||
|
if (a_family == AF_MAX && b_family != AF_MAX) {
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
else if (a_family != AF_MAX && b_family == AF_MAX) {
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
a_family = convert_v6_to_v4(a_family, a_addr);
|
||||||
|
b_family = convert_v6_to_v4(b_family, b_addr);
|
||||||
|
if (a_family == b_family) {
|
||||||
|
retval = memcmp(a_addr, b_addr,
|
||||||
|
a_family == AF_INET ?
|
||||||
|
sizeof(struct in_addr) :
|
||||||
|
sizeof(struct in6_addr));
|
||||||
|
}
|
||||||
|
else if (a_family == AF_INET) {
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
retval = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int sql_strnatcmp(void *ptr,
|
||||||
|
int a_len, const void *a_in,
|
||||||
|
int b_len, const void *b_in)
|
||||||
|
{
|
||||||
|
return strnatcmp(a_len, (char *)a_in, b_len, (char *)b_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int sql_strnatcasecmp(void *ptr,
|
||||||
|
int a_len, const void *a_in,
|
||||||
|
int b_len, const void *b_in)
|
||||||
|
{
|
||||||
|
return strnatcasecmp(a_len, (char *)a_in, b_len, (char *)b_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
int register_collation_functions(sqlite3 *db)
|
||||||
|
{
|
||||||
|
sqlite3_create_collation(db, "ipaddress", SQLITE_UTF8, NULL, ipaddress);
|
||||||
|
sqlite3_create_collation(db, "natural", SQLITE_UTF8, NULL, sql_strnatcmp);
|
||||||
|
sqlite3_create_collation(db, "naturalnocase", SQLITE_UTF8, NULL, sql_strnatcasecmp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2013, Timothy Stack
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @file column_namer.hh
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
class column_namer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
column_namer() {
|
||||||
|
this->cn_builtin_names.push_back("col");
|
||||||
|
};
|
||||||
|
|
||||||
|
bool existing_name(const std::string &in_name) {
|
||||||
|
if (find(this->cn_builtin_names.begin(),
|
||||||
|
this->cn_builtin_names.end(),
|
||||||
|
in_name) != this->cn_builtin_names.end()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (find(this->cn_names.begin(),
|
||||||
|
this->cn_names.end(),
|
||||||
|
in_name) != this->cn_names.end()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string add_column(const std::string &in_name) {
|
||||||
|
std::string base_name = in_name, retval;
|
||||||
|
size_t buf_size;
|
||||||
|
char *buffer;
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
buf_size = in_name.length() + 64;
|
||||||
|
buffer = (char *)alloca(buf_size);
|
||||||
|
if (in_name == "") {
|
||||||
|
base_name = "col";
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = base_name;
|
||||||
|
while (this->existing_name(retval)) {
|
||||||
|
snprintf(buffer, buf_size, "%s_%d", base_name.c_str(), num);
|
||||||
|
retval = buffer;
|
||||||
|
num += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->cn_names.push_back(retval);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> cn_builtin_names;
|
||||||
|
std::vector<std::string> cn_names;
|
||||||
|
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,169 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2013, Timothy Stack
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @file nextwork-extension-functions.cc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "sqlite3.h"
|
||||||
|
|
||||||
|
static void sql_gethostbyname(sqlite3_context *context,
|
||||||
|
int argc, sqlite3_value **argv)
|
||||||
|
{
|
||||||
|
char buffer[INET6_ADDRSTRLEN];
|
||||||
|
const char *name_in;
|
||||||
|
struct addrinfo *ai;
|
||||||
|
void *addr_ptr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
assert(argc >= 1 && argc <= 2);
|
||||||
|
|
||||||
|
if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
|
||||||
|
sqlite3_result_null(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
name_in = (const char *)sqlite3_value_text(argv[0]);
|
||||||
|
while ((rc = getaddrinfo(name_in, NULL, NULL, &ai)) == EAI_AGAIN) {
|
||||||
|
sqlite3_sleep(10);
|
||||||
|
}
|
||||||
|
if (rc != 0) {
|
||||||
|
sqlite3_result_text(context, name_in, -1, SQLITE_TRANSIENT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ai->ai_family) {
|
||||||
|
case AF_INET:
|
||||||
|
addr_ptr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr;
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
addr_ptr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
inet_ntop(ai->ai_family, addr_ptr, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
sqlite3_result_text(context, buffer, -1, SQLITE_TRANSIENT);
|
||||||
|
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sql_gethostbyaddr(sqlite3_context *context,
|
||||||
|
int argc, sqlite3_value **argv)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
} sa;
|
||||||
|
const char *addr_str;
|
||||||
|
char buffer[NI_MAXHOST];
|
||||||
|
int family, socklen;
|
||||||
|
char *addr_raw;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
assert(argc == 1);
|
||||||
|
|
||||||
|
if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
|
||||||
|
sqlite3_result_null(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_str = (const char *)sqlite3_value_text(argv[0]);
|
||||||
|
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
if (strchr(addr_str, ':')) {
|
||||||
|
family = AF_INET6;
|
||||||
|
socklen = sizeof(struct sockaddr_in6);
|
||||||
|
sa.sin6.sin6_family = family;
|
||||||
|
addr_raw = (char *)&sa.sin6.sin6_addr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
family = AF_INET;
|
||||||
|
socklen = sizeof(struct sockaddr_in);
|
||||||
|
sa.sin.sin_family = family;
|
||||||
|
addr_raw = (char *)&sa.sin.sin_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inet_pton(family, addr_str, addr_raw) != 1) {
|
||||||
|
sqlite3_result_text(context, addr_str, -1, SQLITE_TRANSIENT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((rc = getnameinfo((struct sockaddr *)&sa, socklen,
|
||||||
|
buffer, sizeof(buffer), NULL, 0, 0)) == EAI_AGAIN) {
|
||||||
|
sqlite3_sleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc != 0) {
|
||||||
|
sqlite3_result_text(context, addr_str, -1, SQLITE_TRANSIENT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_result_text(context, buffer, -1, SQLITE_TRANSIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int register_network_extension_functions(sqlite3 *db)
|
||||||
|
{
|
||||||
|
static const struct {
|
||||||
|
const char *name;
|
||||||
|
char narg;
|
||||||
|
uint8_t text_rep;
|
||||||
|
void (*func)(sqlite3_context*,int,sqlite3_value**);
|
||||||
|
} plain_funcs[] = {
|
||||||
|
{ "gethostbyname", 1, SQLITE_UTF8, sql_gethostbyname },
|
||||||
|
{ "gethostbyaddr", 1, SQLITE_UTF8, sql_gethostbyaddr },
|
||||||
|
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
for (int lpc = 0; plain_funcs[lpc].name; lpc++) {
|
||||||
|
retval = sqlite3_create_function(db,
|
||||||
|
plain_funcs[lpc].name,
|
||||||
|
plain_funcs[lpc].narg,
|
||||||
|
plain_funcs[lpc].text_rep,
|
||||||
|
NULL,
|
||||||
|
plain_funcs[lpc].func,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
if (retval != SQLITE_OK)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
@ -0,0 +1,209 @@
|
|||||||
|
/* -*- mode: c; c-file-style: "k&r" -*-
|
||||||
|
|
||||||
|
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||||
|
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* partial change history:
|
||||||
|
*
|
||||||
|
* 2004-10-10 mbp: Lift out character type dependencies into macros.
|
||||||
|
*
|
||||||
|
* Eric Sosman pointed out that ctype functions take a parameter whose
|
||||||
|
* value must be that of an unsigned int, even on platforms that have
|
||||||
|
* negative chars in their default char type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "strnatcmp.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* These are defined as macros to make it easier to adapt this code to
|
||||||
|
* different characters types or comparison functions. */
|
||||||
|
static inline int
|
||||||
|
nat_isdigit(nat_char a)
|
||||||
|
{
|
||||||
|
return isdigit((unsigned char) a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
nat_isspace(nat_char a)
|
||||||
|
{
|
||||||
|
return isspace((unsigned char) a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline nat_char
|
||||||
|
nat_toupper(nat_char a)
|
||||||
|
{
|
||||||
|
return toupper((unsigned char) a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_right(int a_len, nat_char const *a, int b_len, nat_char const *b)
|
||||||
|
{
|
||||||
|
int bias = 0;
|
||||||
|
|
||||||
|
/* The longest run of digits wins. That aside, the greatest
|
||||||
|
value wins, but we can't know that it will until we've scanned
|
||||||
|
both numbers to know that they have the same magnitude, so we
|
||||||
|
remember it in BIAS. */
|
||||||
|
for (;; a++, b++, a_len--, b_len--) {
|
||||||
|
if (a_len == 0 && b_len == 0)
|
||||||
|
return 0;
|
||||||
|
if (a_len == 0)
|
||||||
|
return -1;
|
||||||
|
if (b_len == 0)
|
||||||
|
return 1;
|
||||||
|
if (!nat_isdigit(*a) && !nat_isdigit(*b))
|
||||||
|
return bias;
|
||||||
|
else if (!nat_isdigit(*a))
|
||||||
|
return -1;
|
||||||
|
else if (!nat_isdigit(*b))
|
||||||
|
return +1;
|
||||||
|
else if (*a < *b) {
|
||||||
|
if (!bias)
|
||||||
|
bias = -1;
|
||||||
|
} else if (*a > *b) {
|
||||||
|
if (!bias)
|
||||||
|
bias = +1;
|
||||||
|
} else if (!*a && !*b)
|
||||||
|
return bias;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_left(int a_len, nat_char const *a, int b_len, nat_char const *b)
|
||||||
|
{
|
||||||
|
/* Compare two left-aligned numbers: the first to have a
|
||||||
|
different value wins. */
|
||||||
|
for (;; a++, b++, a_len--, b_len--) {
|
||||||
|
if (a_len == 0 && b_len == 0)
|
||||||
|
return 0;
|
||||||
|
if (a_len == 0)
|
||||||
|
return -1;
|
||||||
|
if (b_len == 0)
|
||||||
|
return 1;
|
||||||
|
if (!nat_isdigit(*a) && !nat_isdigit(*b))
|
||||||
|
return 0;
|
||||||
|
else if (!nat_isdigit(*a))
|
||||||
|
return -1;
|
||||||
|
else if (!nat_isdigit(*b))
|
||||||
|
return +1;
|
||||||
|
else if (*a < *b)
|
||||||
|
return -1;
|
||||||
|
else if (*a > *b)
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int strnatcmp0(int a_len, nat_char const *a,
|
||||||
|
int b_len, nat_char const *b,
|
||||||
|
int fold_case)
|
||||||
|
{
|
||||||
|
int ai, bi;
|
||||||
|
nat_char ca, cb;
|
||||||
|
int fractional, result;
|
||||||
|
|
||||||
|
assert(a && b);
|
||||||
|
ai = bi = 0;
|
||||||
|
while (1) {
|
||||||
|
if (ai >= a_len)
|
||||||
|
ca = 0;
|
||||||
|
else
|
||||||
|
ca = a[ai];
|
||||||
|
if (bi >= b_len)
|
||||||
|
cb = 0;
|
||||||
|
else
|
||||||
|
cb = b[bi];
|
||||||
|
|
||||||
|
/* skip over leading spaces or zeros */
|
||||||
|
while (nat_isspace(ca)) {
|
||||||
|
ai += 1;
|
||||||
|
if (ai >= a_len)
|
||||||
|
ca = 0;
|
||||||
|
else
|
||||||
|
ca = a[ai];
|
||||||
|
}
|
||||||
|
|
||||||
|
while (nat_isspace(cb)) {
|
||||||
|
bi += 1;
|
||||||
|
if (bi >= b_len)
|
||||||
|
cb = 0;
|
||||||
|
else
|
||||||
|
cb = b[bi];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process run of digits */
|
||||||
|
if (nat_isdigit(ca) && nat_isdigit(cb)) {
|
||||||
|
fractional = (ca == '0' || cb == '0');
|
||||||
|
|
||||||
|
if (fractional) {
|
||||||
|
if ((result = compare_left(a_len - ai, a+ai, b_len - bi, b+bi)) != 0)
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
if ((result = compare_right(a_len - ai, a+ai, b_len - bi, b+bi)) != 0)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ca && !cb) {
|
||||||
|
/* The strings compare the same. Perhaps the caller
|
||||||
|
will want to call strcmp to break the tie. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fold_case) {
|
||||||
|
ca = nat_toupper(ca);
|
||||||
|
cb = nat_toupper(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ca < cb)
|
||||||
|
return -1;
|
||||||
|
else if (ca > cb)
|
||||||
|
return +1;
|
||||||
|
|
||||||
|
++ai; ++bi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int strnatcmp(int a_len, nat_char const *a, int b_len, nat_char const *b) {
|
||||||
|
return strnatcmp0(a_len, a, b_len, b, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Compare, recognizing numeric string and ignoring case. */
|
||||||
|
int strnatcasecmp(int a_len, nat_char const *a, int b_len, nat_char const *b) {
|
||||||
|
return strnatcmp0(a_len, a, b_len, b, 1);
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/* -*- mode: c; c-file-style: "k&r" -*-
|
||||||
|
|
||||||
|
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||||
|
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* CUSTOMIZATION SECTION
|
||||||
|
*
|
||||||
|
* You can change this typedef, but must then also change the inline
|
||||||
|
* functions in strnatcmp.c */
|
||||||
|
typedef char nat_char;
|
||||||
|
|
||||||
|
int strnatcmp(int a_len, nat_char const *a, int b_len, nat_char const *b);
|
||||||
|
int strnatcasecmp(int a_len, nat_char const *a, int b_len, nat_char const *b);
|
@ -1,17 +1,14 @@
|
|||||||
a=1 b=2 c=3,4
|
a=1 b=2 c=3,4
|
||||||
key 8:9 ^
|
key 0:1 ^ a
|
||||||
sep 9:10 ^
|
num 2:3 ^ 1
|
||||||
num 10:11 ^
|
val 2:3 ^ 1
|
||||||
num 12:13 ^
|
pair 0:3 ^-^ a=1
|
||||||
row 10:13 ^-^
|
key 4:5 ^ b
|
||||||
pair 8:13 ^---^
|
num 6:7 ^ 2
|
||||||
key 4:5 ^
|
val 6:7 ^ 2
|
||||||
sep 5:6 ^
|
pair 4:7 ^-^ b=2
|
||||||
num 6:7 ^
|
key 8:9 ^ c
|
||||||
row 6:7 ^
|
num 10:11 ^ 3
|
||||||
pair 4:7 ^-^
|
num 12:13 ^ 4
|
||||||
key 0:1 ^
|
val 10:13 ^-^ 3,4
|
||||||
sep 1:2 ^
|
pair 8:13 ^---^ c=3,4
|
||||||
num 2:3 ^
|
|
||||||
row 2:3 ^
|
|
||||||
pair 0:3 ^-^
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
current speed: 38 mph
|
current speed: 38 mph
|
||||||
key 0:13 ^-----------^
|
key 0:0
|
||||||
sep 13:14 ^
|
key 0:13 ^-----------^ current speed
|
||||||
num 15:17 ^^
|
pair 0:13 ^-----------^ current speed
|
||||||
word 18:21 ^-^
|
key 15:15 ^
|
||||||
row 15:21 ^----^
|
num 15:17 ^^ 38
|
||||||
pair 0:17 ^---------------^
|
pair 15:17 ^^ 38
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
1,2,3,4,five,six,7
|
1,2,3,4,five,six,7
|
||||||
num 0:1 ^
|
key 0:0
|
||||||
num 2:3 ^
|
num 0:1 ^ 1
|
||||||
num 4:5 ^
|
pair 0:1 ^ 1
|
||||||
num 6:7 ^
|
key 2:2 ^
|
||||||
word 8:12 ^--^
|
num 2:3 ^ 2
|
||||||
word 13:16 ^-^
|
pair 2:3 ^ 2
|
||||||
num 17:18 ^
|
key 4:4 ^
|
||||||
row 0:18 ^----------------^
|
num 4:5 ^ 3
|
||||||
|
pair 4:5 ^ 3
|
||||||
|
key 6:6 ^
|
||||||
|
num 6:7 ^ 4
|
||||||
|
pair 6:7 ^ 4
|
||||||
|
key 17:17 ^
|
||||||
|
num 17:18 ^ 7
|
||||||
|
pair 17:18 ^ 7
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
1 2 3 4 five six 7
|
1 2 3 4 five six 7
|
||||||
num 0:1 ^
|
key 0:0
|
||||||
num 2:3 ^
|
num 0:1 ^ 1
|
||||||
num 4:5 ^
|
pair 0:1 ^ 1
|
||||||
num 6:7 ^
|
key 2:2 ^
|
||||||
word 8:12 ^--^
|
num 2:3 ^ 2
|
||||||
word 13:16 ^-^
|
pair 2:3 ^ 2
|
||||||
num 17:18 ^
|
key 4:4 ^
|
||||||
row 0:18 ^----------------^
|
num 4:5 ^ 3
|
||||||
|
pair 4:5 ^ 3
|
||||||
|
key 6:6 ^
|
||||||
|
num 6:7 ^ 4
|
||||||
|
pair 6:7 ^ 4
|
||||||
|
key 17:17 ^
|
||||||
|
num 17:18 ^ 7
|
||||||
|
pair 17:18 ^ 7
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
the-value: "Hello, World!"
|
the-value: "Hello, World!"
|
||||||
key 0:9 ^-------^
|
key 0:9 ^-------^ the-value
|
||||||
sep 9:10 ^
|
quot 12:25 ^-----------^ Hello, World!
|
||||||
quot 12:25 ^-----------^
|
val 12:25 ^-----------^ Hello, World!
|
||||||
row 12:25 ^-----------^
|
pair 0:25 ^-----------------------^ the-value: "Hello, World!
|
||||||
pair 0:25 ^-----------------------^
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
this is a url: http://www.example.com/foo-bar
|
this is a url: http://www.example.com/foo-bar
|
||||||
key 0:13 ^-----------^
|
key 0:13 ^-----------^ this is a url
|
||||||
sep 13:14 ^
|
url 15:45 ^----------------------------^ http://www.example.com/foo-bar
|
||||||
url 15:45 ^----------------------------^
|
val 15:45 ^----------------------------^ http://www.example.com/foo-bar
|
||||||
row 15:45 ^----------------------------^
|
pair 0:45 ^-------------------------------------------^ this is a url: http://www.example.com/foo-bar
|
||||||
pair 0:45 ^-------------------------------------------^
|
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
qualified:name: foo=1 bar=2
|
qualified:name: foo=1 bar=2
|
||||||
key 22:25 ^-^
|
key 16:19 ^-^ foo
|
||||||
sep 25:26 ^
|
num 20:21 ^ 1
|
||||||
num 26:27 ^
|
val 20:21 ^ 1
|
||||||
row 26:27 ^
|
pair 16:21 ^---^ foo=1
|
||||||
pair 22:27 ^---^
|
key 22:25 ^-^ bar
|
||||||
key 16:19 ^-^
|
num 26:27 ^ 2
|
||||||
sep 19:20 ^
|
val 26:27 ^ 2
|
||||||
num 20:21 ^
|
pair 22:27 ^---^ bar=2
|
||||||
row 20:21 ^
|
|
||||||
pair 16:21 ^---^
|
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
func(arg1="a", arg2="b")
|
||||||
|
key 5:5 ^
|
||||||
|
key 5:9 ^--^ arg1
|
||||||
|
quot 11:12 ^ a
|
||||||
|
val 11:12 ^ a
|
||||||
|
pair 5:12 ^-----^ arg1="a
|
||||||
|
key 15:19 ^--^ arg2
|
||||||
|
quot 21:22 ^ b
|
||||||
|
val 21:22 ^ b
|
||||||
|
pair 15:22 ^-----^ arg2="b
|
||||||
|
grp 5:22 ^---------------^ arg1="a", arg2="b
|
||||||
|
pair 5:22 ^---------------^ arg1="a", arg2="b
|
@ -0,0 +1,31 @@
|
|||||||
|
Succeeded authorizing right 'system.privilege.taskport.debug' by client '/usr/libexec/taskgated' [76339] for authorization created by '/usr/libexec/taskgated' [77395] (100003,1)
|
||||||
|
key 29:29 ^
|
||||||
|
quot 29:60 ^-----------------------------^ system.privilege.taskport.debug
|
||||||
|
pair 29:60 ^-----------------------------^ system.privilege.taskport.debug
|
||||||
|
key 73:73 ^
|
||||||
|
quot 73:95 ^--------------------^ /usr/libexec/taskgated
|
||||||
|
pair 73:95 ^--------------------^ /usr/libexec/taskgated
|
||||||
|
key 98:98 ^
|
||||||
|
key 98:98 ^
|
||||||
|
num 98:103 ^---^ 76339
|
||||||
|
pair 98:103 ^---^ 76339
|
||||||
|
grp 98:103 ^---^ 76339
|
||||||
|
pair 98:103 ^---^ 76339
|
||||||
|
key 135:135 ^
|
||||||
|
quot 135:157 ^--------------------^ /usr/libexec/taskgated
|
||||||
|
pair 135:157 ^--------------------^ /usr/libexec/taskgated
|
||||||
|
key 160:160 ^
|
||||||
|
key 160:160 ^
|
||||||
|
num 160:165 ^---^ 77395
|
||||||
|
pair 160:165 ^---^ 77395
|
||||||
|
grp 160:165 ^---^ 77395
|
||||||
|
pair 160:165 ^---^ 77395
|
||||||
|
key 168:168 ^
|
||||||
|
key 168:168 ^
|
||||||
|
num 168:174 ^----^ 100003
|
||||||
|
pair 168:174 ^----^ 100003
|
||||||
|
key 175:175 ^
|
||||||
|
num 175:176 ^ 1
|
||||||
|
pair 175:176 ^ 1
|
||||||
|
grp 168:176 ^------^ 100003,1
|
||||||
|
pair 168:176 ^------^ 100003,1
|
@ -1,32 +1,20 @@
|
|||||||
Nov 3 09:47:02 veridian sudo: timstack : TTY=pts/6 ; PWD=/auto/wstimstack/rpms/lbuild/test ; USER=root ; COMMAND=/usr/bin/tail /var/log/messages
|
timstack : TTY=pts/6 ; PWD=/auto/wstimstack/rpms/lbuild/test ; USER=root ; COMMAND=/usr/bin/tail /var/log/messages
|
||||||
key 106:113 ^-----^
|
key 11:14 ^-^ TTY
|
||||||
sep 113:114 ^
|
sym 15:18 ^-^ pts
|
||||||
path 114:127 ^-----------^
|
num 19:20 ^ 6
|
||||||
path 128:145 ^---------------^
|
val 15:20 ^---^ pts/6
|
||||||
row 114:145 ^-----------------------------^
|
pair 11:20 ^-------^ TTY=pts/6
|
||||||
pair 106:127 ^-------------------^
|
key 23:26 ^-^ PWD
|
||||||
key 94:98 ^--^
|
path 27:60 ^-------------------------------^ /auto/wstimstack/rpms/lbuild/test
|
||||||
sep 98:99 ^
|
val 27:60 ^-------------------------------^ /auto/wstimstack/rpms/lbuild/test
|
||||||
word 99:103 ^--^
|
pair 23:60 ^-----------------------------------^ PWD=/auto/wstimstack/rpms/lbuild/test
|
||||||
row 99:103 ^--^
|
key 63:67 ^--^ USER
|
||||||
pair 94:103 ^-------^
|
word 68:72 ^--^ root
|
||||||
key 54:57 ^-^
|
val 68:72 ^--^ root
|
||||||
sep 57:58 ^
|
pair 63:72 ^-------^ USER=root
|
||||||
path 58:91 ^-------------------------------^
|
key 75:82 ^-----^ COMMAND
|
||||||
row 58:91 ^-------------------------------^
|
path 83:96 ^-----------^ /usr/bin/tail
|
||||||
pair 54:91 ^-----------------------------------^
|
wspc 96:97 ^
|
||||||
key 42:45 ^-^
|
path 97:114 ^---------------^ /var/log/messages
|
||||||
sep 45:46 ^
|
val 83:114 ^-----------------------------^ /usr/bin/tail /var/log/messages
|
||||||
word 46:49 ^-^
|
pair 75:114 ^-------------------------------------^ COMMAND=/usr/bin/tail /var/log/messages
|
||||||
path 49:51 ^^
|
|
||||||
row 46:51 ^---^
|
|
||||||
pair 42:51 ^-------^
|
|
||||||
key 16:29 ^-----------^
|
|
||||||
sep 29:30 ^
|
|
||||||
word 31:39 ^------^
|
|
||||||
row 31:39 ^------^
|
|
||||||
pair 16:39 ^---------------------^
|
|
||||||
word 0:3 ^-^
|
|
||||||
num 5:6 ^
|
|
||||||
time 7:15 ^------^
|
|
||||||
date 0:15 ^-------------^
|
|
||||||
|
@ -1,33 +1,21 @@
|
|||||||
Jun 18 16:13:52 Tim-Stacks-iMac Safari[81045]: INSERT-HANG-DETECTED: Tx time:3.093364, # of Inserts: 89, # of bytes written: 465365, Did shrink: NO
|
INSERT-HANG-DETECTED: Tx time:3.093364, # of Inserts: 89, # of bytes written: 465365, Did shrink: NO
|
||||||
key 137:143 ^----^
|
key 0:20 ^------------------^ INSERT-HANG-DETECTED
|
||||||
sep 143:144 ^
|
word 22:24 ^^ Tx
|
||||||
word 145:147 ^^
|
val 22:24 ^^ Tx
|
||||||
row 145:147 ^^
|
pair 0:24 ^----------------------^ INSERT-HANG-DETECTED: Tx
|
||||||
pair 137:147 ^--------^
|
key 25:29 ^--^ time
|
||||||
key 107:123 ^--------------^
|
num 30:38 ^------^ 3.093364
|
||||||
sep 123:124 ^
|
val 30:38 ^------^ 3.093364
|
||||||
num 125:131 ^----^
|
pair 25:38 ^-----------^ time:3.093364
|
||||||
word 133:136 ^-^
|
key 40:52 ^----------^ # of Inserts
|
||||||
row 125:136 ^---------^
|
num 54:56 ^^ 89
|
||||||
pair 107:136 ^---------------------------^
|
val 54:56 ^^ 89
|
||||||
key 89:99 ^--------^
|
pair 40:56 ^--------------^ # of Inserts: 89
|
||||||
sep 99:100 ^
|
key 58:76 ^----------------^ # of bytes written
|
||||||
num 101:103 ^^
|
num 78:84 ^----^ 465365
|
||||||
word 105:106 ^
|
val 78:84 ^----^ 465365
|
||||||
row 101:106 ^---^
|
pair 58:84 ^------------------------^ # of bytes written: 465365
|
||||||
pair 89:106 ^---------------^
|
key 86:96 ^--------^ Did shrink
|
||||||
key 72:76 ^--^
|
sym 98:100 ^^ NO
|
||||||
sep 76:77 ^
|
val 98:100 ^^ NO
|
||||||
num 77:85 ^------^
|
pair 86:100 ^------------^ Did shrink: NO
|
||||||
word 87:88 ^
|
|
||||||
row 77:88 ^---------^
|
|
||||||
pair 72:88 ^--------------^
|
|
||||||
key 47:67 ^------------------^
|
|
||||||
sep 67:68 ^
|
|
||||||
word 69:71 ^^
|
|
||||||
row 69:71 ^^
|
|
||||||
pair 47:71 ^----------------------^
|
|
||||||
word 0:3 ^-^
|
|
||||||
num 4:6 ^^
|
|
||||||
time 7:15 ^------^
|
|
||||||
date 0:15 ^-------------^
|
|
||||||
|
Loading…
Reference in New Issue