From: Carl Worth Date: Tue, 22 Nov 2005 23:54:09 +0000 (+0000) Subject: 2005-11-22 Carl Worth X-Git-Url: https://git.cworth.org/git?p=ttt;a=commitdiff_plain;h=c6398c6a1b59f6eddefc9f9ce577017b15677251 2005-11-22 Carl Worth * 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. --- diff --git a/ChangeLog b/ChangeLog index 6effd22..090f1ec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2005-11-22 Carl Worth + + * 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 * src/Makefile.am: diff --git a/TODO b/TODO new file mode 100644 index 0000000..7972fce --- /dev/null +++ b/TODO @@ -0,0 +1,52 @@ + /----- 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 + 2.1.2. NOTICE QUIT + 2.1.3. NOTICE INVITE + 2.1.4. NOTICE DISPOSE + 2.1.5. NOTICE MESSAGE + 2.2. Game notices + 2.2.1. Global game notices + 2.2.1.1. NOTICE NEWGAME + 2.2.1.2. NOTICE GAMEOVER + 2.2.2. Move notices + 2.2.2.1. NOTICE MOVE + 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 diff --git a/configure.in b/configure.in index 73cdd99..96a500f 100644 --- a/configure.in +++ b/configure.in @@ -14,6 +14,7 @@ AM_MAINTAINER_MODE AC_PROG_CC AC_STDC_HEADERS +AM_PROG_LEX dnl =========================================================================== dnl Use lots of warning flags with GCC diff --git a/src/Makefile.am b/src/Makefile.am index 4b336a0..c205ef9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,6 +7,7 @@ ttt_common_sources = \ ttt-board.h \ ttt-error.c \ ttt-error.h \ + ttt-lex.l \ ttt-socket.c \ ttt-socket.h \ x.c \ @@ -22,5 +23,6 @@ ttt_server_SOURCES = \ 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 diff --git a/src/ttt-client.c b/src/ttt-client.c index 9d44945..8139ada 100644 --- a/src/ttt-client.c +++ b/src/ttt-client.c @@ -21,9 +21,11 @@ #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; @@ -31,34 +33,35 @@ struct _ttt_client { 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 @@ -73,97 +76,76 @@ _ttt_client_fini (ttt_client_t *client) 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; } diff --git a/src/ttt-lex.h b/src/ttt-lex.h new file mode 100644 index 0000000..84463a2 --- /dev/null +++ b/src/ttt-lex.h @@ -0,0 +1,316 @@ +#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 +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +#include +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 +#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 */ diff --git a/src/ttt-lex.l b/src/ttt-lex.l new file mode 100644 index 0000000..2a9d8e2 --- /dev/null +++ b/src/ttt-lex.l @@ -0,0 +1,16 @@ + /* 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] ; diff --git a/src/ttt-token.h b/src/ttt-token.h new file mode 100644 index 0000000..f063d60 --- /dev/null +++ b/src/ttt-token.h @@ -0,0 +1,33 @@ +/* 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 + */ + +#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_ */ diff --git a/ylwrap b/ylwrap new file mode 100755 index 0000000..102bd89 --- /dev/null +++ b/ylwrap @@ -0,0 +1,223 @@ +#! /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 . +# +# 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 or send patches to +# . + +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 . +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: