| /* | |
| * Utility routines | |
| * | |
| * Copyright 1998 Bertho A. Stultiens | |
| * Copyright 2002 Ove Kaaven | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library 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 | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include "config.h" | |
| #include <assert.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <stdarg.h> | |
| #include <string.h> | |
| #include <ctype.h> | |
| #include "widl.h" | |
| #include "utils.h" | |
| #include "parser.h" | |
| void error_at( const struct location *where, const char *s, ... ) | |
| { | |
| char buffer[1024]; | |
| va_list ap; | |
| va_start( ap, s ); | |
| vsnprintf( buffer, sizeof(buffer), s, ap ); | |
| va_end( ap ); | |
| parser_error( where, buffer ); | |
| exit( 1 ); | |
| } | |
| void error(const char *s, ...) | |
| { | |
| va_list ap; | |
| va_start(ap, s); | |
| fprintf(stderr, "error: "); | |
| vfprintf(stderr, s, ap); | |
| va_end(ap); | |
| exit(2); | |
| } | |
| void warning(const char *s, ...) | |
| { | |
| va_list ap; | |
| va_start(ap, s); | |
| fprintf(stderr, "warning: "); | |
| vfprintf(stderr, s, ap); | |
| va_end(ap); | |
| } | |
| void warning_at( const struct location *where, const char *s, ... ) | |
| { | |
| char buffer[1024]; | |
| va_list ap; | |
| va_start( ap, s ); | |
| vsnprintf( buffer, sizeof(buffer), s, ap ); | |
| va_end( ap ); | |
| parser_warning( where, buffer ); | |
| } | |
| void chat(const char *s, ...) | |
| { | |
| if(debuglevel & DEBUGLEVEL_CHAT) | |
| { | |
| va_list ap; | |
| va_start(ap, s); | |
| fprintf(stderr, "chat: "); | |
| vfprintf(stderr, s, ap); | |
| va_end(ap); | |
| } | |
| } | |
| size_t widl_getline(char **linep, size_t *lenp, FILE *fp) | |
| { | |
| char *line = *linep; | |
| size_t len = *lenp; | |
| size_t n = 0; | |
| if (!line) | |
| { | |
| len = 64; | |
| line = xmalloc(len); | |
| } | |
| while (fgets(&line[n], len - n, fp)) | |
| { | |
| n += strlen(&line[n]); | |
| if (line[n - 1] == '\n') | |
| break; | |
| else if (n == len - 1) | |
| { | |
| len *= 2; | |
| line = xrealloc(line, len); | |
| } | |
| } | |
| *linep = line; | |
| *lenp = len; | |
| return n; | |
| } | |
| void strappend( struct strbuf *str, const char *fmt, ... ) | |
| { | |
| va_list ap; | |
| int n; | |
| assert( (str->len == 0 && str->buf == NULL) || | |
| (str->len != 0 && str->buf != NULL) ); | |
| for (;;) | |
| { | |
| va_start( ap, fmt ); | |
| n = str->len ? vsnprintf( str->buf + str->pos, str->len - str->pos, fmt, ap ) : 128; | |
| va_end( ap ); | |
| if (n >= 0 && n <= str->len && str->pos + n < str->len) break; | |
| str->len = max( str->pos + n, str->len * 3 / 2 ); | |
| str->buf = xrealloc( str->buf, str->len ); | |
| } | |
| str->pos += n; | |
| } | |
| /******************************************************************* | |
| * buffer management | |
| * | |
| * Function for writing to a memory buffer. | |
| */ | |
| unsigned char *output_buffer; | |
| size_t output_buffer_pos; | |
| size_t output_buffer_size; | |
| static struct resource | |
| { | |
| unsigned char *data; | |
| size_t size; | |
| } resources[16]; | |
| static unsigned int nb_resources; | |
| static inline void put_resource_id( const char *str ) | |
| { | |
| if (str[0] != '#') | |
| { | |
| while (*str) | |
| { | |
| unsigned char ch = *str++; | |
| put_word( toupper(ch) ); | |
| } | |
| put_word( 0 ); | |
| } | |
| else | |
| { | |
| put_word( 0xffff ); | |
| put_word( atoi( str + 1 )); | |
| } | |
| } | |
| void add_output_to_resources( const char *type, const char *name ) | |
| { | |
| size_t data_size = output_buffer_pos; | |
| size_t header_size = 5 * sizeof(unsigned int) + 2 * sizeof(unsigned short); | |
| assert( nb_resources < ARRAY_SIZE( resources )); | |
| if (type[0] != '#') header_size += (strlen( type ) + 1) * sizeof(unsigned short); | |
| else header_size += 2 * sizeof(unsigned short); | |
| if (name[0] != '#') header_size += (strlen( name ) + 1) * sizeof(unsigned short); | |
| else header_size += 2 * sizeof(unsigned short); | |
| header_size = (header_size + 3) & ~3; | |
| align_output( 4 ); | |
| check_output_buffer_space( header_size ); | |
| resources[nb_resources].size = header_size + output_buffer_pos; | |
| memmove( output_buffer + header_size, output_buffer, output_buffer_pos ); | |
| output_buffer_pos = 0; | |
| put_dword( data_size ); /* ResSize */ | |
| put_dword( header_size ); /* HeaderSize */ | |
| put_resource_id( type ); /* ResType */ | |
| put_resource_id( name ); /* ResName */ | |
| align_output( 4 ); | |
| put_dword( 0 ); /* DataVersion */ | |
| put_word( 0 ); /* Memory options */ | |
| put_word( 0 ); /* Language */ | |
| put_dword( 0 ); /* Version */ | |
| put_dword( 0 ); /* Characteristics */ | |
| resources[nb_resources++].data = output_buffer; | |
| init_output_buffer(); | |
| } | |
| void flush_output_resources( const char *name ) | |
| { | |
| unsigned int i; | |
| /* all output must have been saved with add_output_to_resources() first */ | |
| assert( !output_buffer_pos ); | |
| put_dword( 0 ); /* ResSize */ | |
| put_dword( 32 ); /* HeaderSize */ | |
| put_word( 0xffff ); /* ResType */ | |
| put_word( 0x0000 ); | |
| put_word( 0xffff ); /* ResName */ | |
| put_word( 0x0000 ); | |
| put_dword( 0 ); /* DataVersion */ | |
| put_word( 0 ); /* Memory options */ | |
| put_word( 0 ); /* Language */ | |
| put_dword( 0 ); /* Version */ | |
| put_dword( 0 ); /* Characteristics */ | |
| for (i = 0; i < nb_resources; i++) | |
| { | |
| put_data( resources[i].data, resources[i].size ); | |
| free( resources[i].data ); | |
| } | |
| flush_output_buffer( name ); | |
| nb_resources = 0; | |
| } | |
| /* pointer-sized word */ | |
| void put_pword( unsigned int val ) | |
| { | |
| if (pointer_size == 8) put_qword( val ); | |
| else put_dword( val ); | |
| } | |
| void put_str( int indent, const char *format, ... ) | |
| { | |
| int n; | |
| va_list args; | |
| check_output_buffer_space( 4 * indent ); | |
| memset( output_buffer + output_buffer_pos, ' ', 4 * indent ); | |
| output_buffer_pos += 4 * indent; | |
| for (;;) | |
| { | |
| size_t size = output_buffer_size - output_buffer_pos; | |
| va_start( args, format ); | |
| n = vsnprintf( (char *)output_buffer + output_buffer_pos, size, format, args ); | |
| va_end( args ); | |
| if (n == -1) size *= 2; | |
| else if ((size_t)n >= size) size = n + 1; | |
| else | |
| { | |
| output_buffer_pos += n; | |
| return; | |
| } | |
| check_output_buffer_space( size ); | |
| } | |
| } |