+2005-11-22 Carl Worth <cworth@cworth.org>
+
+ * TODO: Add TODO file listing all the stuff from the protocol that
+ needs to be implemented.
+
+ * src/Makefile.am:
+ * configure.in:
+ * ylwrap:
+ * src/ttt-lex.h:
+ * src/ttt-lex.l:
+ * src/ttt-token.h: Add support for a flex-based tokenizer which
+ tokenizes newlines and space-separated strings.
+
+ * src/ttt-client.c: (_ttt_client_init), (_ttt_client_fini),
+ (_append_to_request), (_free_request), (_read_request),
+ (_execute_request): Use new tokenizer to tokenize input into an
+ array of request strings.
+
2005-11-15 Carl Worth <cworth@cworth.org>
* src/Makefile.am:
--- /dev/null
+ /----- Server, implemented in ttt-server
+ / /---- Client, implemented in ttt
+S C
+ 1. Requests
+ 1.1 HELO
+ 1.2. Global commands
+ 1.2.1. WHO
+ 1.2.2. MESSAGE
+ 1.2.3. HELP
+ 1.2.4. QUIT
+ 1.2.5. VERSION
+ 1.3. Game management commands
+ 1.3.1. INVITE
+ 1.3.2. ACCEPT
+ 1.4. In-game commands
+ 1.4.1. SHOW
+ 1.4.2. PART
+ 1.4.3. MOVE
+ 2. Asynchronous notification.
+ 2.1. Global notices
+ 2.1.1. NOTICE USER <username>
+ 2.1.2. NOTICE QUIT <username>
+ 2.1.3. NOTICE INVITE <username>
+ 2.1.4. NOTICE DISPOSE <game>
+ 2.1.5. NOTICE MESSAGE <username> <text>
+ 2.2. Game notices
+ 2.2.1. Global game notices
+ 2.2.1.1. NOTICE NEWGAME <username> <username>
+ 2.2.1.2. NOTICE GAMEOVER <outcome> <username>
+ 2.2.2. Move notices
+ 2.2.2.1. NOTICE MOVE <username> <number>
+ 3. Errors
+ 3.1. Connection setup errors
+ 3.1.1. ERROR NONAMESET
+ 3.1.2. ERROR INVALIDNAME
+ 3.2. Command format errors
+ 3.2.1. ERROR COMMAND
+ 3.2.2. ERROR SYNTAX
+ 3.2.3. ERROR NOTNUMBER
+ 3.2.4. ERROR NOTGRID
+ 3.3. Global command errors.
+ 3.4. Game management errors.
+ 3.4.1. ERROR NOGAME
+ 3.5. User information errors
+ 3.5.1. ERROR NOUSER
+ 3.6. In-game errors
+ 3.6.1. Global game errors
+ 3.6.1.1. ERROR NOTINGAME
+ 3.6.1.2. ERROR NOTPLAYING
+ 3.6.2. Moving errors
+ 3.6.2.1. ERROR NOTYOURTURN
+
\ No newline at end of file
AC_PROG_CC
AC_STDC_HEADERS
+AM_PROG_LEX
dnl ===========================================================================
dnl Use lots of warning flags with GCC
ttt-board.h \
ttt-error.c \
ttt-error.h \
+ ttt-lex.l \
ttt-socket.c \
ttt-socket.h \
x.c \
ttt-server.c
AM_CFLAGS = $(WARN_CFLAGS) $(TTT_CFLAGS)
+AM_LFLAGS = --header-file=ttt-lex.h -Cr
ttt_client_LDFLAGS = $(TTT_LIBS)
ttt_server_LDFLAGS = $(TTT_LIBS) -lpthread
#include "ttt-client.h"
+#include "ttt-error.h"
+#include "ttt-lex.h"
#include "ttt-server.h"
#include "ttt-socket.h"
-#include "ttt-error.h"
+#include "ttt-token.h"
struct _ttt_client {
pthread_mutex_t mutex;
ttt_server_t *server;
int socket;
+ yyscan_t scanner;
int id;
- char buf[TTT_CLIENT_BUF_SIZE];
- char *buf_head;
- char *buf_tail;
-
- char *request;
- int request_size;
- int request_len;
+ char **request_strings;
+ int num_request_strings;
};
+static void
+_free_request (ttt_client_t *client);
+
static void
_ttt_client_init (ttt_client_t *client,
ttt_server_t *server,
int socket)
{
+ FILE *file;
+
pthread_mutex_init (&client->mutex, NULL);
client->server = server;
client->socket = socket;
- client->buf_head = client->buf;
- client->buf_tail = client->buf;
+ file = xfdopen (socket, "r");
+ yylex_init(&client->scanner);
+ yyset_in (file, client->scanner);
- client->request = NULL;
- client->request_size = 0;
- client->request_len = 0;
+ client->request_strings = NULL;
+ client->num_request_strings = 0;
/* XXX: Probably want to register only as the result of the HELO
command. Not only will that match the protocol correctly, but
ttt_server_unregister_client (client->server, client);
+ yylex_destroy (client->scanner);
shutdown (client->socket, SHUT_RDWR);
- free (client->request);
+ _free_request (client);
pthread_mutex_unlock (&client->mutex);
pthread_mutex_destroy (&client->mutex);
}
+/* XXX: The memory management for the request strings is pretty cheesy. */
static void
_append_to_request (ttt_client_t *client,
- const char *buf,
- int size)
+ const char *string)
{
- int size_needed = client->request_len + size;
-
- if (size_needed > client->request_size) {
- if (client->request_size == 0) {
- client->request_size = size_needed;
- } else {
- while (size_needed > client->request_size)
- client->request_size *= 2;
- }
+ client->num_request_strings++;
+ client->request_strings =
+ xrealloc (client->request_strings,
+ client->num_request_strings * sizeof (char *));
- client->request = xrealloc (client->request, client->request_size);
- }
-
- memcpy (client->request + client->request_len,
- buf, size);
-
- client->request_len += size;
+ client->request_strings[client->num_request_strings - 1] = xstrdup (string);
}
-static ttt_status_t
-_read_into_request_until (ttt_client_t *client, char delimeter)
+static void
+_free_request (ttt_client_t *client)
{
- ttt_bool_t found_delimeter = FALSE;
- int bytes_read;
- char *s;
+ int i;
- client->request_len = 0;
+ for (i = 0; i < client->num_request_strings; i++)
+ free (client->request_strings[i]);
- while (1) {
+ free (client->request_strings);
- if (client->buf_tail >= client->buf_head) {
- bytes_read = xread (client->socket,
- client->buf,
- TTT_CLIENT_BUF_SIZE);
- if (bytes_read == 0)
- return TTT_STATUS_EOF;
- client->buf_head = client->buf;
- client->buf_tail = client->buf_head + bytes_read;
- }
-
- for (s = client->buf_head; s < client->buf_tail; s++) {
- if (*s == delimeter) {
- found_delimeter = TRUE;
- s++;
- break;
- }
- }
-
- _append_to_request (client,
- client->buf_head,
- s - client->buf_head);
- client->buf_head = s;
-
- if (found_delimeter)
- return TTT_STATUS_SUCCESS;
- }
+ client->request_strings = NULL;
+ client->num_request_strings = 0;
}
static ttt_status_t
_read_request (ttt_client_t *client)
{
- ttt_status_t status;
- static const char null_terminator = '\0';
+ ttt_token_t token;
+
+ _free_request (client);
- status = _read_into_request_until (client, '\n');
- if (status)
- return status;
+ while (1) {
+ token = yylex (client->scanner);
+ /* Yes, EOF in two different enums is pretty ugly. */
+ if (token == TTT_TOKEN_EOF)
+ return TTT_STATUS_EOF;
+
+ if (token == TTT_TOKEN_NEWLINE) {
+ if (client->num_request_strings)
+ return TTT_STATUS_SUCCESS;
+ else
+ continue;
+ }
- _append_to_request (client, &null_terminator, 1);
+ assert (token == TTT_TOKEN_STRING);
- return TTT_STATUS_SUCCESS;
+ _append_to_request (client, yyget_text (client->scanner));
+ }
}
static ttt_error_t
_execute_request (ttt_client_t *client)
{
- ttt_server_broadcast (client->server, client->request);
+ int i;
+
+ for (i=0; i < client->num_request_strings; i++)
+ ttt_server_broadcast (client->server, client->request_strings[i]);
return TTT_ERROR_NONE;
}
--- /dev/null
+#ifndef yyHEADER_H
+#define yyHEADER_H 1
+#define yyIN_HEADER 1
+
+#line 6 "ttt-lex.h"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 31
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+int yylex_init (yyscan_t* scanner);
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+void yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void yypop_buffer_state (yyscan_t yyscanner );
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void yyfree (void * ,yyscan_t yyscanner );
+
+#define yytext_ptr yytext_r
+
+#ifdef YY_HEADER_EXPORT_START_CONDITIONS
+#define INITIAL 0
+
+#endif
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (yyscan_t yyscanner );
+
+int yyget_debug (yyscan_t yyscanner );
+
+void yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *yyget_in (yyscan_t yyscanner );
+
+void yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *yyget_out (yyscan_t yyscanner );
+
+void yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+int yyget_leng (yyscan_t yyscanner );
+
+char *yyget_text (yyscan_t yyscanner );
+
+int yyget_lineno (yyscan_t yyscanner );
+
+void yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (yyscan_t yyscanner );
+#else
+extern int yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (yyscan_t yyscanner);
+
+#define YY_DECL int yylex (yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+#undef YY_NEW_FILE
+#undef YY_FLUSH_BUFFER
+#undef yy_set_bol
+#undef yy_new_buffer
+#undef yy_set_interactive
+#undef yytext_ptr
+#undef YY_DO_BEFORE_ACTION
+
+#ifdef YY_DECL_IS_OURS
+#undef YY_DECL_IS_OURS
+#undef YY_DECL
+#endif
+#line 15 "ttt-lex.l"
+
+#line 317 "ttt-lex.h"
+#undef yyIN_HEADER
+#endif /* yyHEADER_H */
--- /dev/null
+ /* Definitions */
+
+%option reentrant
+%option noyywrap
+
+%{
+#include "ttt-token.h"
+%}
+
+%%
+
+ /* Rules */
+
+\r\n return TTT_TOKEN_NEWLINE;
+[^ \t\r\n][^ \t\r\n]* return TTT_TOKEN_STRING;
+[ \t\r\n] ;
--- /dev/null
+/* ttt-token.h - token types
+ *
+ * Copyright © 2005 Carl Worth
+ *
+ * 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, 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 Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Carl Worth <cworth@cworth.org>
+ */
+
+#include "ttt.h"
+
+#ifndef _TTT_TOKEN_H_
+#define _TTT_TOKEN_H_
+
+typedef enum {
+ TTT_TOKEN_EOF = 0,
+ TTT_TOKEN_STRING,
+ TTT_TOKEN_NEWLINE
+} ttt_token_t;
+
+#endif /* _TTT_TOKEN_H_ */
--- /dev/null
+#! /bin/sh
+# ylwrap - wrapper for lex/yacc invocations.
+
+scriptversion=2005-05-14.22
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# 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, 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
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case "$1" in
+ '')
+ echo "$0: No files given. Try \`$0 --help' for more information." 1>&2
+ exit 1
+ ;;
+ --basedir)
+ basedir=$2
+ shift 2
+ ;;
+ -h|--h*)
+ cat <<\EOF
+Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
+
+Wrapper for lex/yacc invocations, renaming files as desired.
+
+ INPUT is the input file
+ OUTPUT is one file PROG generates
+ DESIRED is the file we actually want instead of OUTPUT
+ PROGRAM is program to run
+ ARGS are passed to PROG
+
+Any number of OUTPUT,DESIRED pairs may be used.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v|--v*)
+ echo "ylwrap $scriptversion"
+ exit $?
+ ;;
+esac
+
+
+# The input.
+input="$1"
+shift
+case "$input" in
+ [\\/]* | ?:[\\/]*)
+ # Absolute path; do nothing.
+ ;;
+ *)
+ # Relative path. Make it absolute.
+ input="`pwd`/$input"
+ ;;
+esac
+
+pairlist=
+while test "$#" -ne 0; do
+ if test "$1" = "--"; then
+ shift
+ break
+ fi
+ pairlist="$pairlist $1"
+ shift
+done
+
+# The program to run.
+prog="$1"
+shift
+# Make any relative path in $prog absolute.
+case "$prog" in
+ [\\/]* | ?:[\\/]*) ;;
+ *[\\/]*) prog="`pwd`/$prog" ;;
+esac
+
+# FIXME: add hostname here for parallel makes that run commands on
+# other machines. But that might take us over the 14-char limit.
+dirname=ylwrap$$
+trap "cd `pwd`; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15
+mkdir $dirname || exit 1
+
+cd $dirname
+
+case $# in
+ 0) $prog "$input" ;;
+ *) $prog "$@" "$input" ;;
+esac
+ret=$?
+
+if test $ret -eq 0; then
+ set X $pairlist
+ shift
+ first=yes
+ # Since DOS filename conventions don't allow two dots,
+ # the DOS version of Bison writes out y_tab.c instead of y.tab.c
+ # and y_tab.h instead of y.tab.h. Test to see if this is the case.
+ y_tab_nodot="no"
+ if test -f y_tab.c || test -f y_tab.h; then
+ y_tab_nodot="yes"
+ fi
+
+ # The directory holding the input.
+ input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'`
+ # Quote $INPUT_DIR so we can use it in a regexp.
+ # FIXME: really we should care about more than `.' and `\'.
+ input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'`
+
+ while test "$#" -ne 0; do
+ from="$1"
+ # Handle y_tab.c and y_tab.h output by DOS
+ if test $y_tab_nodot = "yes"; then
+ if test $from = "y.tab.c"; then
+ from="y_tab.c"
+ else
+ if test $from = "y.tab.h"; then
+ from="y_tab.h"
+ fi
+ fi
+ fi
+ if test -f "$from"; then
+ # If $2 is an absolute path name, then just use that,
+ # otherwise prepend `../'.
+ case "$2" in
+ [\\/]* | ?:[\\/]*) target="$2";;
+ *) target="../$2";;
+ esac
+
+ # We do not want to overwrite a header file if it hasn't
+ # changed. This avoid useless recompilations. However the
+ # parser itself (the first file) should always be updated,
+ # because it is the destination of the .y.c rule in the
+ # Makefile. Divert the output of all other files to a temporary
+ # file so we can compare them to existing versions.
+ if test $first = no; then
+ realtarget="$target"
+ target="tmp-`echo $target | sed s/.*[\\/]//g`"
+ fi
+ # Edit out `#line' or `#' directives.
+ #
+ # We don't want the resulting debug information to point at
+ # an absolute srcdir; it is better for it to just mention the
+ # .y file with no path.
+ #
+ # We want to use the real output file name, not yy.lex.c for
+ # instance.
+ #
+ # We want the include guards to be adjusted too.
+ FROM=`echo "$from" | sed \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
+ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
+ TARGET=`echo "$2" | sed \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
+ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
+
+ sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \
+ -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$?
+
+ # Check whether header files must be updated.
+ if test $first = no; then
+ if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
+ echo "$2" is unchanged
+ rm -f "$target"
+ else
+ echo updating "$2"
+ mv -f "$target" "$realtarget"
+ fi
+ fi
+ else
+ # A missing file is only an error for the first file. This
+ # is a blatant hack to let us support using "yacc -d". If -d
+ # is not specified, we don't want an error when the header
+ # file is "missing".
+ if test $first = yes; then
+ ret=1
+ fi
+ fi
+ shift
+ shift
+ first=no
+ done
+else
+ ret=$?
+fi
+
+# Remove the directory.
+cd ..
+rm -rf $dirname
+
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End: