#include "config.h"
#include "system.h"
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "genindex.h"
extern void warning PARAMS ((const char *, ...));
enum index_language_kind index_language = PB_INDEX_LANGUAGE_INVALID;
#define DEBUG_INDEXING 1
#define MAX_INDEX_FILENAME_SIZE 1024
int flag_debug_gen_index = 0;
int flag_gen_index = 0;
int flag_gen_index_original = 0;
int flag_gen_index_header = 0;
int flag_suppress_builtin_indexing = 0;
static int skip_index_generation = 0;
static int recursion_depth = 0;
static int indexed_header_list_dirty = 0;
static int index_socket_fd = -1;
static char *index_host_name = 0;
static char *index_port_string = 0;
static unsigned index_port_number = 0;
static int MAX_BEGIN_COUNT = 4096;
int begin_header_count = 0;
char **begin_header_stack = NULL;
struct idx_file_stack
{
char *name;
struct idx_file_stack *next;
};
static struct idx_file_stack *cur_index_filename = NULL;
#define CUR_INDEX_FILENAME (cur_index_filename ? cur_index_filename->name: NULL)
int flag_check_indexed_header_list = 0;
char *index_header_list_filename = 0;
struct indexed_header
{
struct indexed_header *next;
char *name;
struct idx_file_stack *dup_name;
time_t timestamp;
int timestamp_status;
int status;
};
enum {
INDEX_TIMESTAMP_INVALID,
INDEX_TIMESTAMP_NOT_VALIDATED,
INDEX_TIMESTAMP_VALID
};
static struct indexed_header *indexed_header_list = NULL;
static void allocate_begin_header_stack PARAMS ((void));
static void reallocate_begin_header_stack PARAMS ((void));
static void push_begin_header_stack PARAMS ((char *));
static char * pop_begin_header_stack PARAMS ((void));
static void maybe_flush_index_buffer PARAMS ((int));
static void allocate_index_buffer PARAMS ((void));
static char * absolute_path_name PARAMS ((char *));
static int is_dup_name PARAMS ((struct idx_file_stack *, char *));
static void free_idx_file_stack PARAMS (( struct idx_file_stack *));
static struct idx_file_stack * push_idx_file_stack
PARAMS (( struct idx_file_stack *, const char *));
static struct idx_file_stack * pop_idx_file_stack
PARAMS (( struct idx_file_stack *));
int
connect_to_socket (hostname, port_number)
char *hostname;
unsigned port_number;
{
int socket_fd;
struct sockaddr_in addr;
memset ((char *)&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = (hostname == NULL) ?
INADDR_LOOPBACK :
inet_addr (hostname);
addr.sin_port = htons (port_number);
socket_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socket_fd < 0)
{
warning("cannot create socket: %s", strerror (errno));
return -1;
}
if (connect (socket_fd, (struct sockaddr *)&addr, sizeof (addr)) < 0)
{
warning("cannot connect to socket: %s", strerror (errno));
return -1;
}
return socket_fd;
}
void
disable_gen_index ()
{
flag_gen_index = flag_debug_gen_index = flag_gen_index_original = 0;
}
void
init_gen_indexing ()
{
if (flag_gen_index || flag_debug_gen_index)
{
index_header_list_filename = getenv ("PB_INDEXED_HEADERS_FILE");
if (index_header_list_filename && *index_header_list_filename)
{
read_indexed_header_list ();
flag_check_indexed_header_list = 1;
}
}
if (flag_debug_gen_index)
{
flag_gen_index = 1;
flag_gen_index_original = 1;
flag_gen_index_header = 1;
return;
}
index_port_string = getenv ("PB_INDEX_SOCKET_PORT");
if (index_port_string && *index_port_string)
{
index_port_number = atoi (index_port_string);
flag_gen_index = 1;
flag_gen_index_original = 1;
flag_gen_index_header = 1;
index_host_name = getenv ("PB_INDEX_SOCKET_HOSTNAME");
if (index_host_name && *index_host_name)
{ }
else
index_host_name = NULL;
}
if (flag_gen_index)
{
index_socket_fd = connect_to_socket (index_host_name,
index_port_number);
if (index_socket_fd == -1)
{
warning ("Indexing information is not produced.");
flag_gen_index = 0;
}
else
flag_debug_gen_index = 0;
}
}
void
finish_gen_indexing ()
{
if (!flag_debug_gen_index)
if (close (index_socket_fd) < 0)
warning ("cannot close the indexing data socket");
if (flag_check_indexed_header_list)
write_indexed_header_list ();
}
char *index_buffer = NULL;
int index_buffer_count = 0;
#define INDEX_BUFFER_SIZE 16000
static void
allocate_index_buffer ()
{
if (index_buffer == NULL)
index_buffer = (char *) xcalloc (INDEX_BUFFER_SIZE, sizeof (char));
}
void
flush_index_buffer ()
{
int l = 0;
if (flag_debug_gen_index)
fprintf (stderr, "%s", index_buffer);
else
{
l = write (index_socket_fd, (void *)index_buffer, strlen (index_buffer));
if (l < (int) strlen (index_buffer))
warning("Indexing socket communication error.\n");
}
free (index_buffer);
index_buffer_count = 0;
index_buffer = NULL;
}
static void
maybe_flush_index_buffer (i)
int i;
{
if ((index_buffer_count + i) > (INDEX_BUFFER_SIZE - 20))
flush_index_buffer();
allocate_index_buffer ();
}
void
gen_indexing_info (info_tag, name, number)
int info_tag;
const char *name;
int number;
{
int extra_length = 20;
int info_length = 0;
int name_length = 0;
char nbuf[12];
char info[6];
if (flag_suppress_builtin_indexing)
return;
switch (info_tag)
{
case INDEX_ENUM:
case INDEX_VAR_DECL:
strcpy (info, "+vm ");
break;
case INDEX_FILE_BEGIN:
strcpy (info, "+Fm ");
break;
case INDEX_FILE_INCLUDE:
strcpy (info, "+Fi ");
break;
case INDEX_FILE_END:
strcpy (info, "-Fm ");
break;
case INDEX_FUNCTION_BEGIN:
strcpy (info, "+fm ");
break;
case INDEX_FUNCTION_END:
strcpy (info, "-fm ");
break;
case INDEX_FUNCTION_DECL:
strcpy (info, "+fh ");
break;
case INDEX_CONST_DECL:
strcpy (info, "+nh ");
break;
case INDEX_TYPE_DECL:
strcpy (info, "+th ");
break;
case INDEX_PROTOCOL_BEGIN:
strcpy (info, "+Pm ");
break;
case INDEX_PROTOCOL_END:
strcpy (info, "-Pm ");
break;
case INDEX_PROTOCOL_INHERITANCE:
strcpy (info, "+Pi ");
break;
case INDEX_CATEGORY_BEGIN:
strcpy (info, "+Cm ");
break;
case INDEX_CATEGORY_END:
strcpy (info, "-Cm ");
break;
case INDEX_CATEGORY_DECL:
strcpy (info, "+Ch ");
break;
case INDEX_CATEGORY_DECL_END:
strcpy (info, "-Ch ");
break;
case INDEX_CLASS_METHOD_BEGIN:
case INDEX_CLASS_OPERATOR_BEGIN:
strcpy (info, "++m ");
break;
case INDEX_CLASS_METHOD_END:
strcpy (info, "-+m ");
break;
case INDEX_CLASS_METHOD_DECL:
case INDEX_CLASS_OPERATOR_DECL:
strcpy (info, "++h ");
break;
case INDEX_INSTANCE_METHOD_BEGIN:
case INDEX_INSTANCE_OPERATOR_BEGIN:
case INDEX_CONSTRUCTOR_BEGIN:
strcpy (info, "+-m ");
break;
case INDEX_INSTANCE_METHOD_END:
strcpy (info, "--m ");
break;
case INDEX_INSTANCE_METHOD_DECL:
case INDEX_INSTANCE_OPERATOR_DECL:
case INDEX_CONSTRUCTOR_DECL:
strcpy (info, "+-h ");
break;
case INDEX_DESTRUCTOR_BEGIN:
strcpy (info, "+-m ");
break;
case INDEX_DESTRUCTOR_DECL:
strcpy (info, "+-h ");
break;
case INDEX_MACRO:
strcpy (info, "+Mh ");
break;
case INDEX_DATA_DECL:
strcpy (info, "+dh ");
break;
case INDEX_DATA_INHERITANCE:
strcpy (info, "+di ");
break;
case INDEX_NAMESPACE_DECL:
strcpy (info, "+Nh ");
break;
case INDEX_CLASS_DECL:
strcpy (info, "+ch ");
break;
case INDEX_CLASS_DECL_END:
strcpy (info, "-ch ");
break;
case INDEX_CLASS_BEGIN:
strcpy (info, "+cm ");
break;
case INDEX_CLASS_END:
strcpy (info, "-cm ");
break;
case INDEX_CLASS_INHERITANCE:
strcpy (info, "+ci ");
break;
case INDEX_RECORD_BEGIN:
strcpy (info, "+sm ");
break;
case INDEX_RECORD_END:
strcpy (info, "-sm ");
break;
case INDEX_UNION_BEGIN:
strcpy (info, "+um ");
break;
case INDEX_UNION_END:
strcpy (info, "-um ");
break;
case INDEX_ERROR:
default:
fprintf (stderr,"indexing error: invalid info_tag\n");
return;
break;
}
if (info)
info_length = strlen (info);
if (name)
name_length = strlen (name);
maybe_flush_index_buffer (info_length + name_length + extra_length);
if (info)
{
strcpy (index_buffer + index_buffer_count, info);
index_buffer_count += info_length;
if (index_language != PB_INDEX_LANGUAGE_INVALID)
{
index_buffer_count += sprintf (index_buffer + index_buffer_count,
"%d ", index_language);
}
}
if (number != -1)
{
index_buffer_count += sprintf (index_buffer + index_buffer_count,
"%u ", number);
}
if (name)
{
if (info_tag == INDEX_DESTRUCTOR_BEGIN
|| info_tag == INDEX_DESTRUCTOR_DECL)
{
memcpy(&index_buffer[index_buffer_count], "~", 1);
index_buffer_count++;
index_buffer [index_buffer_count] = NULL;
}
if (info_tag == INDEX_INSTANCE_OPERATOR_DECL
|| info_tag == INDEX_CLASS_OPERATOR_DECL
|| info_tag == INDEX_INSTANCE_OPERATOR_BEGIN
|| info_tag == INDEX_CLASS_OPERATOR_BEGIN)
{
memcpy(&index_buffer[index_buffer_count], "operator ", 9);
index_buffer_count += 9;
index_buffer [index_buffer_count] = NULL;
}
strcpy (index_buffer + index_buffer_count, name);
index_buffer_count += name_length;
}
memcpy(&index_buffer[index_buffer_count], "\n", 1);
index_buffer_count++;
index_buffer [index_buffer_count] = NULL;
}
void gen_indexing_header (name)
char *name;
{
char *header;
int len = strlen (name);
int components;
int len_header;
components = 1;
header = (char *) xmalloc (sizeof (char) * (40 + len));
len_header = sprintf (header, "pbxindex-begin v1.2 0x%08lX %02u/%02u %s\n",
(unsigned long) getppid(), components, components, name);
maybe_flush_index_buffer (len_header);
strcpy (index_buffer + index_buffer_count, header);
index_buffer_count += len_header;
free (header);
}
void gen_indexing_footer ()
{
const char *footer = "pbxindex-end ?\n";
int len = strlen (footer);
maybe_flush_index_buffer (len);
strcpy (index_buffer + index_buffer_count, footer);
index_buffer_count += len;
}
int
read_indexed_header_list ()
{
char buffer[MAX_INDEX_FILENAME_SIZE];
struct indexed_header *cursor;
FILE *file;
char *name = NULL;
time_t timestamp = 0;
int i, length = 0;
file = fopen (index_header_list_filename, "r");
if (!file)
return 0;
while (fgets (buffer, MAX_INDEX_FILENAME_SIZE, file))
{
length = strlen (buffer);
while (length > 0 && buffer [length - 1] <= ' ')
buffer [-- length] = '\0';
for (i = 0; i < length; i++)
{
if (buffer [i] == ' ')
{
name = &buffer [i+1];
buffer [i] = NULL;
timestamp = atol (buffer);
break;
}
}
cursor = add_index_header (name, timestamp);
if (cursor)
{
cursor->status = PB_INDEX_DONE;
cursor->timestamp_status = INDEX_TIMESTAMP_NOT_VALIDATED;
}
}
indexed_header_list_dirty = 0;
fclose (file);
return 1;
}
void
write_indexed_header_list ()
{
FILE *file;
struct indexed_header *cursor;
if (indexed_header_list_dirty == 0)
return;
file = fopen (index_header_list_filename, "w");
if (!file)
return;
for (cursor = indexed_header_list;
cursor != NULL;
cursor = cursor->next)
{
if (cursor->timestamp_status != INDEX_TIMESTAMP_INVALID
&& cursor->status == PB_INDEX_DONE)
fprintf (file, "%ld %s\n", cursor->timestamp, cursor->name);
}
fclose (file);
}
struct indexed_header *
add_index_header_name (str)
char *str;
{
struct stat buf;
if (!str)
return NULL;
if (stat(str, &buf))
return NULL;
return add_index_header (str, buf.st_mtime);
}
struct indexed_header *
add_index_header (str, timestamp)
char *str;
time_t timestamp;
{
struct indexed_header *h;
h = (struct indexed_header *) xmalloc (sizeof (struct indexed_header));
if (!h)
return NULL;
h->dup_name = NULL;
h->name = (char *) xmalloc (sizeof (char) * (strlen (str) + 1));
if (!h->name)
return NULL;
strcpy (h->name,str);
h->timestamp = timestamp;
h->next = indexed_header_list;
indexed_header_list = h;
indexed_header_list_dirty = 1;
return h;
}
void
push_cur_index_filename (name)
const char *name;
{
cur_index_filename = push_idx_file_stack (cur_index_filename, name);
}
void
pop_cur_index_filename ()
{
cur_index_filename = pop_idx_file_stack (cur_index_filename);
}
void
add_dup_header_name (orig_name, sname)
const char *orig_name;
const char *sname;
{
struct indexed_header *cursor;
if (!sname || !orig_name)
return;
for (cursor = indexed_header_list;
cursor != NULL;
cursor = cursor->next)
{
if (!strcmp (cursor->name, CUR_INDEX_FILENAME))
cursor->dup_name = push_idx_file_stack (cursor->dup_name, sname);
}
}
static int
is_dup_name (struct idx_file_stack *d, char *n)
{
struct idx_file_stack *cursor;
if (!d || !n)
return 0;
for (cursor = d; cursor != NULL; cursor = cursor->next)
if (cursor->name && !strcmp (cursor->name, n))
return 1;
return 0;
}
void
print_indexed_header_list ()
{
int count = 0;
struct indexed_header *cursor;
for (cursor = indexed_header_list; cursor != NULL; cursor = cursor->next)
{
fprintf (stderr, "[%d] %d", count, cursor->timestamp_status);
switch (cursor->status)
{
case PB_INDEX_UNKNOWN:
fprintf (stderr, " PB_INDEX_UNKNOWN"); break;
case PB_INDEX_SEEN:
fprintf (stderr, " PB_INDEX_SEEN"); break;
case PB_INDEX_RECURSIVE:
fprintf (stderr, " PB_INDEX_RECURSIVE"); break;
case PB_INDEX_DONE:
fprintf (stderr, " PB_INDEX_DONE"); break;
default:
fprintf (stderr, " Invalid status"); break;
}
if (cursor->name)
fprintf (stderr, " %s\n", cursor->name);
else
fprintf (stderr, " Invalid names\n");
count++;
}
}
void
free_idx_file_stack (list)
struct idx_file_stack *list;
{
struct idx_file_stack *cursor;
struct idx_file_stack *next_cursor;
cursor = next_cursor = list;
for (; next_cursor != NULL; )
{
next_cursor = cursor->next;
free (cursor->name);
free (cursor);
}
}
void
free_indexed_header_list ()
{
struct indexed_header *cursor;
struct indexed_header *next_cursor;
cursor = next_cursor = indexed_header_list;
for ( ; next_cursor != NULL; )
{
next_cursor = cursor->next;
free (cursor->name);
free (cursor);
free_idx_file_stack (cursor->dup_name);
}
while (cur_index_filename)
cur_index_filename = pop_idx_file_stack (cur_index_filename);
return;
}
void
update_header_status (header, when, found)
struct indexed_header *header;
int when;
int found;
{
if (header == NULL)
return;
if (when == PB_INDEX_BEGIN)
{
if (found == 1)
{
skip_index_generation++;
flag_gen_index = 0;
}
else
{
switch (header->status)
{
case PB_INDEX_UNKNOWN:
if (skip_index_generation == 0)
{
header->status = PB_INDEX_SEEN;
flag_gen_index = 1;
gen_indexing_info (INDEX_FILE_INCLUDE, header->name, -1);
gen_indexing_info (INDEX_FILE_BEGIN, header->name, -1);
}
else
{
skip_index_generation++;
header->status = PB_INDEX_DONE;
flag_gen_index = 0;
}
break;
case PB_INDEX_SEEN:
case PB_INDEX_RECURSIVE:
recursion_depth++;
header->status = PB_INDEX_RECURSIVE;
flag_gen_index = 0;
break;
case PB_INDEX_DONE:
warning("Invalid index header status PB_INDEX_DONE encountered.");
warning("Indexing information is not generated properly.");
break;
default:
warning("Invalid index header status encountered.");
warning("Indexing information is not generated properly.");
break;
}
}
}
else if (when == PB_INDEX_END)
{
if (found == 1)
{
skip_index_generation--;
}
else
{
switch (header->status)
{
case PB_INDEX_UNKNOWN:
case PB_INDEX_SEEN:
header->status = PB_INDEX_DONE;
gen_indexing_info (INDEX_FILE_END, header->name, -1);
break;
case PB_INDEX_RECURSIVE:
recursion_depth--;
header->status = PB_INDEX_SEEN;
break;
case PB_INDEX_DONE:
warning("Invalid index header status PB_INDEX_DONE encountered.");
warning("Indexing information is not generated properly.");
break;
default:
warning("Invalid index header status encountered.");
warning("Indexing information is not generated properly.");
break;
}
}
if (skip_index_generation == 0 && recursion_depth == 0)
{
flag_gen_index = 1;
}
else if (skip_index_generation < 0)
{
warning("Invalid skip header index count.");
warning("Indexing information is not generated properly.");
}
else if (recursion_depth < 0)
{
warning("Invalid recursion depth count.");
warning("Indexing information is not generated properly.");
}
}
}
static void
allocate_begin_header_stack ()
{
begin_header_stack = xmalloc (sizeof (char *) * MAX_BEGIN_COUNT);
}
static void
reallocate_begin_header_stack ()
{
begin_header_stack = xrealloc (begin_header_stack, MAX_BEGIN_COUNT);
}
static char *
pop_begin_header_stack ()
{
if (begin_header_count < 0)
{
warning("Invalid begin_header_count");
warning("Indexing information is not generated properly.");
return NULL;
}
begin_header_count = begin_header_count - 1;
return begin_header_stack [ begin_header_count];
}
static void
push_begin_header_stack (name)
char *name;
{
if (begin_header_count == 0)
allocate_begin_header_stack ();
else if (begin_header_count >= MAX_BEGIN_COUNT)
{
MAX_BEGIN_COUNT = 2 * MAX_BEGIN_COUNT;
reallocate_begin_header_stack ();
}
begin_header_stack [ begin_header_count ] = name;
begin_header_count++;
return;
}
static char *
absolute_path_name(input_name)
char *input_name;
{
char *name;
if (input_name[0] != '/')
{
int alen = MAXPATHLEN + strlen (input_name) + 2;
name = (char *) xmalloc (sizeof (char) * alen);
name = getcwd(name, alen);
strcat (name, "/");
strcat (name, input_name);
}
else
{
name = (char *) xmalloc (strlen (input_name) + 1);
strcpy (name, input_name);
}
return name;
}
int
process_header_indexing (input_name, when)
char *input_name;
int when;
{
struct indexed_header *cursor = NULL;
struct stat buf;
int found = 0;
char *name = NULL;
#if 1
name = absolute_path_name (input_name);
#endif
if (!name)
return 0;
for (cursor = indexed_header_list; cursor != NULL; cursor = cursor->next)
{
if (!strcmp (cursor->name, name)
|| (cursor->dup_name
&& CUR_INDEX_FILENAME
&& !strcmp (CUR_INDEX_FILENAME, cursor->name)
&& is_dup_name (cursor->dup_name, name)))
{
if (cursor->timestamp_status == INDEX_TIMESTAMP_VALID)
{
if (cursor->status == PB_INDEX_DONE)
found = 1;
break;
}
else if (cursor->timestamp_status == INDEX_TIMESTAMP_INVALID)
{
found = 0;
}
else if (!stat(name, &buf) && buf.st_mtime == cursor->timestamp)
{
cursor->timestamp_status = INDEX_TIMESTAMP_VALID;
if (cursor->status == PB_INDEX_DONE)
found = 1;
break;
}
else
{
cursor->timestamp_status = INDEX_TIMESTAMP_INVALID;
found = 0;
}
}
}
if (!found)
{
if (!cursor)
{
cursor = add_index_header_name (name);
if (cursor)
{
cursor->status = PB_INDEX_UNKNOWN;
cursor->timestamp_status = INDEX_TIMESTAMP_VALID;
}
}
}
update_header_status (cursor, when, found);
return found;
}
void
set_index_lang (l)
int l;
{
index_language = l;
}
static struct idx_file_stack *
push_idx_file_stack (stack, name)
struct idx_file_stack *stack;
const char *name;
{
struct idx_file_stack *n;
n = (struct idx_file_stack *) xmalloc (sizeof (struct idx_file_stack));
n->name = absolute_path_name (name);
if (stack)
n->next = stack;
else
n->next = NULL;
stack = n;
return stack;
}
static struct idx_file_stack *
pop_idx_file_stack (stack)
struct idx_file_stack *stack;
{
struct idx_file_stack *n = stack;
if (stack)
stack = n->next;
if (n)
{
free (n->name);
free (n);
}
return stack;
}