1997-11-25 06:05:25 +08:00
|
|
|
/* The GIMP -- an image manipulation program
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
1998-04-13 13:44:11 +08:00
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
1997-11-25 06:05:25 +08:00
|
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <glib.h>
|
|
|
|
#include "general.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* prune filename removes all of the leading path information to a filename */
|
|
|
|
|
|
|
|
char *
|
|
|
|
prune_filename (char *filename)
|
|
|
|
{
|
|
|
|
char *last_slash = filename;
|
|
|
|
|
|
|
|
while (*filename)
|
|
|
|
if (*filename++ == '/')
|
|
|
|
last_slash = filename;
|
|
|
|
|
|
|
|
return last_slash;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char*
|
|
|
|
search_in_path (char *search_path,
|
|
|
|
char *filename)
|
|
|
|
{
|
|
|
|
static char path[256];
|
|
|
|
char *local_path, *token;
|
|
|
|
struct stat buf;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
local_path = g_strdup (search_path);
|
|
|
|
token = strtok (local_path, ":");
|
|
|
|
|
|
|
|
while (token)
|
|
|
|
{
|
|
|
|
sprintf (path, "%s", token);
|
|
|
|
|
|
|
|
if (token[strlen (token) - 1] != '/')
|
|
|
|
strcat (path, "/");
|
|
|
|
strcat (path, filename);
|
|
|
|
|
|
|
|
err = stat (path, &buf);
|
|
|
|
if (!err && S_ISREG (buf.st_mode))
|
|
|
|
{
|
|
|
|
token = path;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
token = strtok (NULL, ":");
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (local_path);
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****/
|
|
|
|
|
|
|
|
/* FIXME: This is straight from the GNU libc sources. We should use
|
|
|
|
* autoconf to test for a system having strsep() and similar
|
|
|
|
* stuff... then use HAVE_STRSEP to decide whether to include or not
|
|
|
|
* our own functions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
char *
|
|
|
|
xstrsep (char **pp,
|
|
|
|
char *delim)
|
|
|
|
{
|
|
|
|
char *p, *q;
|
|
|
|
|
|
|
|
if (!(p = *pp))
|
|
|
|
return NULL;
|
|
|
|
if ((q = strpbrk (p, delim))) {
|
|
|
|
*pp = q + 1;
|
|
|
|
*q = '\0';
|
|
|
|
} else
|
|
|
|
*pp = NULL;
|
|
|
|
|
|
|
|
return p;
|
|
|
|
} /* xstrsep */
|
|
|
|
|
|
|
|
|
|
|
|
char *token_str;
|
|
|
|
char *token_sym;
|
|
|
|
double token_num;
|
|
|
|
int token_int;
|
|
|
|
|
|
|
|
int
|
|
|
|
get_token (ParseInfo *info)
|
|
|
|
{
|
|
|
|
char *buffer;
|
|
|
|
char *tokenbuf;
|
|
|
|
int tokenpos = 0;
|
|
|
|
int state;
|
|
|
|
int count;
|
|
|
|
int slashed;
|
|
|
|
|
|
|
|
state = 0;
|
|
|
|
buffer = info->buffer;
|
|
|
|
tokenbuf = info->tokenbuf;
|
|
|
|
slashed = FALSE;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if (info->inc_charnum && info->charnum)
|
|
|
|
info->charnum += 1;
|
|
|
|
if (info->inc_linenum && info->linenum)
|
|
|
|
{
|
|
|
|
info->linenum += 1;
|
|
|
|
info->charnum = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
info->inc_linenum = FALSE;
|
|
|
|
info->inc_charnum = FALSE;
|
|
|
|
|
|
|
|
if (info->position >= (info->buffer_size - 1))
|
|
|
|
info->position = -1;
|
|
|
|
if ((info->position == -1) || (buffer[info->position] == '\0'))
|
|
|
|
{
|
|
|
|
info->position = 0;
|
|
|
|
count = fread (buffer, sizeof (char), info->buffer_size - 1, info->fp);
|
|
|
|
if ((count == 0) && feof (info->fp))
|
|
|
|
return TOKEN_EOF;
|
|
|
|
buffer[count] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
info->inc_charnum = TRUE;
|
|
|
|
if ((buffer[info->position] == '\n') ||
|
|
|
|
(buffer[info->position] == '\r'))
|
|
|
|
info->inc_linenum = TRUE;
|
|
|
|
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if (buffer[info->position] == '#')
|
|
|
|
{
|
|
|
|
info->position += 1;
|
|
|
|
state = 4;
|
|
|
|
}
|
|
|
|
else if (buffer[info->position] == '(')
|
|
|
|
{
|
|
|
|
info->position += 1;
|
|
|
|
return TOKEN_LEFT_PAREN;
|
|
|
|
}
|
|
|
|
else if (buffer[info->position] == ')')
|
|
|
|
{
|
|
|
|
info->position += 1;
|
|
|
|
return TOKEN_RIGHT_PAREN;
|
|
|
|
}
|
|
|
|
else if (buffer[info->position] == '"')
|
|
|
|
{
|
|
|
|
info->position += 1;
|
|
|
|
state = 1;
|
|
|
|
slashed = FALSE;
|
|
|
|
}
|
|
|
|
else if ((buffer[info->position] == '-') || isdigit (buffer[info->position]))
|
|
|
|
{
|
|
|
|
tokenbuf[tokenpos++] = buffer[info->position];
|
|
|
|
info->position += 1;
|
|
|
|
state = 3;
|
|
|
|
}
|
|
|
|
else if ((buffer[info->position] != ' ') &&
|
|
|
|
(buffer[info->position] != '\t') &&
|
|
|
|
(buffer[info->position] != '\n') &&
|
|
|
|
(buffer[info->position] != '\r'))
|
|
|
|
{
|
|
|
|
tokenbuf[tokenpos++] = buffer[info->position];
|
|
|
|
info->position += 1;
|
|
|
|
state = 2;
|
|
|
|
}
|
|
|
|
else if (buffer[info->position] == '\'')
|
|
|
|
{
|
|
|
|
info->position += 1;
|
|
|
|
state = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
info->position += 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if ((buffer[info->position] == '\\') && (!slashed))
|
|
|
|
{
|
|
|
|
slashed = TRUE;
|
|
|
|
info->position += 1;
|
|
|
|
}
|
|
|
|
else if (slashed || (buffer[info->position] != '"'))
|
|
|
|
{
|
|
|
|
slashed = FALSE;
|
|
|
|
tokenbuf[tokenpos++] = buffer[info->position];
|
|
|
|
info->position += 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tokenbuf[tokenpos] = '\0';
|
|
|
|
token_str = tokenbuf;
|
|
|
|
token_sym = tokenbuf;
|
|
|
|
info->position += 1;
|
|
|
|
return TOKEN_STRING;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if ((buffer[info->position] != ' ') &&
|
|
|
|
(buffer[info->position] != '\t') &&
|
|
|
|
(buffer[info->position] != '\n') &&
|
|
|
|
(buffer[info->position] != '\r') &&
|
|
|
|
(buffer[info->position] != '"') &&
|
|
|
|
(buffer[info->position] != '(') &&
|
|
|
|
(buffer[info->position] != ')'))
|
|
|
|
{
|
|
|
|
tokenbuf[tokenpos++] = buffer[info->position];
|
|
|
|
info->position += 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tokenbuf[tokenpos] = '\0';
|
|
|
|
token_sym = tokenbuf;
|
|
|
|
return TOKEN_SYMBOL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if (isdigit (buffer[info->position]) ||
|
|
|
|
(buffer[info->position] == '.'))
|
|
|
|
{
|
|
|
|
tokenbuf[tokenpos++] = buffer[info->position];
|
|
|
|
info->position += 1;
|
|
|
|
}
|
|
|
|
else if ((buffer[info->position] != ' ') &&
|
|
|
|
(buffer[info->position] != '\t') &&
|
|
|
|
(buffer[info->position] != '\n') &&
|
|
|
|
(buffer[info->position] != '\r') &&
|
|
|
|
(buffer[info->position] != '"') &&
|
|
|
|
(buffer[info->position] != '(') &&
|
|
|
|
(buffer[info->position] != ')'))
|
|
|
|
{
|
|
|
|
tokenbuf[tokenpos++] = buffer[info->position];
|
|
|
|
info->position += 1;
|
|
|
|
state = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tokenbuf[tokenpos] = '\0';
|
|
|
|
token_sym = tokenbuf;
|
|
|
|
token_num = atof (tokenbuf);
|
|
|
|
token_int = atoi (tokenbuf);
|
|
|
|
return TOKEN_NUMBER;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
if (buffer[info->position] == '\n')
|
|
|
|
state = 0;
|
|
|
|
info->position += 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse "line" and look for a string of characters without spaces
|
|
|
|
following a '(' and copy them into "token_r". Return the number of
|
|
|
|
characters stored, or 0. */
|
|
|
|
int
|
|
|
|
find_token (char *line,
|
|
|
|
char *token_r,
|
|
|
|
int maxlen)
|
|
|
|
{
|
|
|
|
char *sp;
|
|
|
|
char *dp;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* FIXME: This should be replaced by a more intelligent parser which
|
|
|
|
checks for '\', '"' and nested parentheses. See get_token(). */
|
|
|
|
for (sp = line; *sp; sp++)
|
|
|
|
if (*sp == '(' || *sp == '#')
|
|
|
|
break;
|
|
|
|
if (*sp == '\000' || *sp == '#')
|
|
|
|
{
|
|
|
|
*token_r = '\000';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
dp = token_r;
|
|
|
|
sp++;
|
|
|
|
i = 0;
|
|
|
|
while ((*sp != '\000') && (*sp != ' ') && (*sp != '\t') && i < maxlen)
|
|
|
|
{
|
|
|
|
*dp = *sp;
|
|
|
|
dp++;
|
|
|
|
sp++;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (*sp == '\000' || i >= maxlen)
|
|
|
|
{
|
|
|
|
*token_r = '\000';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*dp = '\000';
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Generate a string containing the date and time and return a pointer
|
|
|
|
to it. If user_buf is not NULL, the string is stored in that
|
|
|
|
buffer (21 bytes). If strict is FALSE, the 'T' between the date
|
|
|
|
and the time is replaced by a space, which makes the format a bit
|
|
|
|
more readable (IMHO). */
|
|
|
|
char *
|
|
|
|
iso_8601_date_format (char *user_buf, int strict)
|
|
|
|
{
|
|
|
|
static char static_buf[21];
|
|
|
|
char *buf;
|
|
|
|
time_t clock;
|
|
|
|
struct tm *now;
|
|
|
|
|
|
|
|
if (user_buf != NULL)
|
|
|
|
buf = user_buf;
|
|
|
|
else
|
|
|
|
buf = static_buf;
|
|
|
|
clock = time (NULL);
|
|
|
|
now = gmtime (&clock);
|
|
|
|
/* date format derived from ISO 8601:1988 */
|
|
|
|
sprintf(buf, "%04d-%02d-%02d%c%02d:%02d:%02d%c",
|
|
|
|
now->tm_year + 1900, now->tm_mon + 1, now->tm_mday,
|
|
|
|
(strict ? 'T' : ' '),
|
|
|
|
now->tm_hour, now->tm_min, now->tm_sec,
|
|
|
|
(strict ? 'Z' : '\000'));
|
|
|
|
return buf;
|
|
|
|
}
|