1 /*
2 *
3 *
4 * RCS Modification History:
5 * $Log: ma_intfc.c,v $
6 * Revision 6.0  1997/08/25 18:36:18  madden
7 * Revision changed to 6.0
8 *
9 * Revision 1.2  1995/05/17 17:54:55  epstein
10 * add RCS log revision history
11 *
12 */
13 
14 #include <stdlib.h>
15 #include "xalloc.h"
16 #include "ma_intfc.h"
17 
18 extern	ma_Obj	mfmt_ASN1_text, mfmt_ASN1_binary;
19 
20 typedef	struct	ma_Hand {
21 	char	*cmd_flag;
22 	char	*handler_name;
23 	char	*load_path;
24 	char	*loadob_sym;
25 	ma_Obj	*object;
26 	void	*handle;
27 	void	*data;
28 	int	 unusable;
29 } ma_Hand;
30 
31 ma_Hand	default_handler_table[] = {
32 
33    {	/* Handle the ASN1 text interface */
34 	"asn1",
35 	"ASN1 Text",
36 	NULL,
37 	"_mfmt_ASN1_text",
38 	&mfmt_ASN1_text,
39 	(void *) NULL,
40 	(void *) NULL,
41 	FALSE
42     },
43 
44    {	/* Handle the ASN1 binary interface */
45 	"asn1b",
46 	"ASN1 Binary",
47 	NULL,
48 	"_mfmt_ASN1_binary",
49 	&mfmt_ASN1_binary,
50 	(void *) NULL,
51 	(void *) NULL,
52 	FALSE
53     }
54 };
55 static	int	n_default_handlers =
56 			sizeof(default_handler_table)/sizeof(ma_Hand);
57 
58 
59 static
60 ma_Hand	handler_table[ MAX_FORMAT_HANDLERS ];
61 static	int	n_handlers = 0;
62 
63 
64 static
strdup(char * s)65 char	*strdup( char *s ) {
66 	char	*r;
67 
68 	if( s == NULL ) return( NULL );
69 
70 	r = xalloc( strlen(s) + 1 );
71 	strcpy(r, s );
72 	return( r );
73 }
74 
75 static
install_format(char * file_name,char * cmd_flag,char * load_path,ma_Obj * object,char * load_symbol,char * handler_name)76 int	install_format( char *file_name, char *cmd_flag, char *load_path,
77 			ma_Obj *object, char *load_symbol, char *handler_name )
78 {
79     char	*config_file;
80 
81     /* Check the arguments */
82 
83     config_file = (file_name == NULL) ? "built-in's" : file_name;
84     if( cmd_flag != NULL && handler_name == NULL ) handler_name = cmd_flag;
85     if( handler_name == NULL ) handler_name = "<<Unknown handler>>";
86     if( cmd_flag == NULL ) {
87 	fprintf(stderr, "%s: No format name flag specified for %s handler\n",
88 		config_file, handler_name );
89 	return( FALSE );
90     }
91     if( load_path == NULL && file_name != NULL ) {
92 	fprintf(stderr, "%s: No load path given for %s handler\n",
93 		config_file, handler_name );
94 	return( FALSE );
95     }
96     if( load_symbol == NULL ) {
97 	fprintf(stderr, "%s: No load symbol given for %s handler\n",
98 		config_file, handler_name );
99 	return( FALSE );
100     }
101 
102     /* Install the entry */
103 
104     if( n_handlers >= MAX_FORMAT_HANDLERS ) {
105 	fprintf(stderr, "%s: Too many handlers at handler %s (%d MAX)\n",
106 		config_file, handler_name, MAX_FORMAT_HANDLERS );
107 	return( FALSE );
108     }
109     handler_table[n_handlers].cmd_flag = cmd_flag;
110     handler_table[n_handlers].handler_name = handler_name;
111     handler_table[n_handlers].load_path = load_path;
112     handler_table[n_handlers].object = object;
113     handler_table[n_handlers].loadob_sym = load_symbol;
114     n_handlers++;
115 
116     return( TRUE );
117 }
118 
119 typedef enum { begin_scan, in_token, quoted_char, quoted_string, end_scan }
120 	State;
121 
122 static
get_token(char * s,char ** next)123 char	*get_token( char *s, char **next )
124 {
125     static char	 token[MAX_TOKEN_SIZE];
126     char	*t = &token[0];
127     State 	 state, old_state;
128     char	 mark;
129 
130     /* Scan out the token */
131 
132     if( s != NULL ) {
133 	for( state = begin_scan; state != end_scan; ) {
134 
135 	    /* White space is all equivalent */
136 
137 	    if( isspace( *s ) || *s == '\r' || *s == '\n' )
138 		*s = ' ';
139 
140 	    switch( state ) {
141 	    case begin_scan:
142 		switch( *s ) {
143 		    case '"':
144 		    case '\'':			/* Quoted strings */
145 			mark = *s;
146 			state = quoted_string;
147 			break;
148 		    case 0:			/* End of string */
149 			state = end_scan;
150 			/* DROP THROUGH */
151 		    case ' ':			/* Spaces - ignore */
152 			break;
153 		    default:			/* Standard token */
154 			state = in_token;
155 			continue;		/* We'll retest this char */
156 		}
157 		break;
158 	    case in_token:			/* Standard token */
159 		switch( *s ) {
160 		    case ' ':	/* Space - terminate the token */
161 		    case 0:			/* End of input */
162 			 state = end_scan;
163 			 break;
164 		    case '\\':			/* Quoted character? */
165 			old_state = state;
166 			state = quoted_char;
167 			break;
168 		    default:
169 			*t++ = *s;
170 			break;		/* Continue collecting */
171 		}
172 		break;
173 	    case quoted_string:		/* String inside quotes */
174 		if( *s == 0 )
175 		    state == end_scan;
176 		else if( *s == mark ) {
177 		    state = old_state;
178 		    break;
179 		} else if( *s == '\\' ) {
180 		    old_state = state;
181 		    state = quoted_char;
182 		} else {
183 		    *t++ = *s;
184 		}
185 		break;
186 	    case quoted_char:		/* Quoted char (\x) */
187 		if( *s == 0 )
188 		    state = end_scan;
189 		else {
190 		    state = old_state;
191 		    *t++ = *s;
192 		}
193 		break;
194 	    }
195 	    if( *s != (char) 0 ) s++;
196 	}
197     }
198     *t++ = (char) 0;			/* Terminate token */
199 
200     /* Figure out where the next token is */
201 
202     if( next != (char **) NULL ) {
203 	*next = ( s == NULL || *s == (char) 0 ) ? NULL : s;
204     }
205 
206     /* Done */
207 
208     return( (*token == (char) 0) ? NULL : token );
209 }
210 
211 
212 static
get_handlers(char * file_name)213 int	get_handlers( char *file_name )
214 {
215     FILE	*fd;
216     char	 buffer[MAX_FORMAT_LINE];
217     int		 rv = TRUE;
218     char	*token;
219 
220     /* Open the configuration file */
221 
222     fd = fopen( file_name, "r" );
223     if( fd == NULL ) {
224 	perror( file_name );
225 	return( FALSE );
226     }
227 
228     /* Read the file and extract the handler lines */
229 
230     while( fgets( buffer, sizeof(buffer), fd ) != NULL ) {
231 	char	*next;
232 	char	*label = get_token( buffer, &next );
233 	if( label == NULL || *label == '#' )
234 		continue;		/* Ignore me type lines */
235 	if( strcmp( label, "format" ) == 0 ) {
236 	    char	*cmd_flag, *load_path, *load_symbol, *handler_name;
237 
238 	    cmd_flag = strdup( get_token( next, &next ) );
239 	    load_path = strdup( get_token( next, &next ) );
240 	    load_symbol = strdup( get_token( next, &next ) );
241 	    handler_name = strdup( get_token( next, &next ) );
242 	    rv &= install_format( file_name, cmd_flag, load_path,
243 		(ma_Obj *) NULL, load_symbol, handler_name);
244 
245 	} else if( strcmp( label, "include" ) == 0 ) {
246 	    while( (token = get_token( next, &next )) != NULL ) {
247 		char	file_name[MAX_TOKEN_SIZE];
248 
249 		strcpy( file_name, token );
250 		rv &= get_handlers( file_name );
251 	    }
252 	}
253     }
254 
255     /* Return the status */
256 
257     return( rv );
258 }
259 
260 
261 /*ARGSUSED*/
ma_GetHandlers(char * file_name)262 int	ma_GetHandlers( char *file_name )
263 {
264 #ifdef	DEBUG
265 	/* DEBUG VERSION - Uses hard coded table */
266 
267 	n_handlers = sizeof(handler_table)/sizeof(ma_Hand);
268 	return( TRUE );
269 #else
270     int	rv = TRUE;		/* Assume everything OK */
271     int i;
272 
273     /* Open the configuration file and read the data */
274 
275     if( file_name != NULL ) rv = get_handlers( file_name );
276 
277     /* Install the default handlers */
278 
279     for( i = 0; i < n_default_handlers; i++ ) {
280 	ma_Hand *h = &default_handler_table[i];
281 	rv &= install_format( NULL, h->cmd_flag, h->load_path,
282 		h->object, h->loadob_sym, h->handler_name );
283     }
284 #endif
285 }
286 
287 
ma_ValidHandler(char * cmd_flag)288 void	*ma_ValidHandler( char *cmd_flag )
289 {
290     register int i;
291 
292     /* Search the handler table for a key.  Only one file can be open
293        on a channel, so we'll look only at closed channels */
294 
295     for( i = 0; i < n_handlers; i++ )
296 	if( handler_table[i].data == NULL &&
297 	    	strcmp( handler_table[i].cmd_flag, cmd_flag ) == 0 )
298 	    return( &handler_table[i] );
299 
300     /* If we didn't find one - we didn't have a slot for it. */
301 
302     return( NULL );
303 }
304 
305 
ma_OpenHandler(void * x_handler,char * file_name,FILE * fd)306 int	ma_OpenHandler( void *x_handler, char *file_name, FILE *fd )
307 {
308     ma_Hand	*handler = x_handler;
309     int		 rv;
310 
311     /* Open the library */
312 
313     if( handler->load_path != NULL ) {
314 	handler->handle = dlopen( handler->load_path, RTLD_LAZY );
315 	if( handler->handle == NULL ) goto err;
316 
317 	/* Get the object from the module */
318 
319 	handler->object = dlsym( handler->handle, handler->loadob_sym );
320     }
321     if( handler->object == NULL )
322 	goto err;
323 
324     /* Initialize the channel */
325 
326     handler->data = handler->object->initialize( handler->handler_name,
327 	handler->object->data );
328     if( handler->data == NULL )
329 	goto err;
330 
331     /* If the file pointer is NULL - we'll open it; otherwise, we assume
332 	that the file is already open (usually stdout) */
333 
334     if( fd != NULL)
335 	rv = handler->object->setup_file( handler->data, file_name, fd );
336     else
337 	rv = handler->object->open_file( handler->data, file_name );
338 
339     /* Successful exit */
340 
341     if( rv ) return( True );
342 
343     /* Come here on an error */
344 err:
345 	handler->unusable = TRUE;
346 	return( FALSE );
347 }
348 
349 
ma_WriteArticle(void * x_handler,MedArt * article)350 int	ma_WriteArticle( void *x_handler, MedArt *article )
351 {
352     ma_Hand	*handler = x_handler;
353     /* If the handler is usable - use it */
354 
355     if( handler->unusable )
356 	return( FALSE );
357 
358     return( handler->object->process( handler->data, article ) );
359 }
360 
361 
ma_CloseHandler(void * x_handler)362 int	ma_CloseHandler( void *x_handler )
363 {
364     ma_Hand	*handler = x_handler;
365 
366     /* We don't have to do anything if it was never opened */
367 
368     if( handler->object != NULL && handler->data != NULL ) {
369 	(void) handler->object->close( handler->data );
370 	handler->data = NULL;
371     }
372 
373     /* Close the object module */
374 
375     if( handler->handle != NULL ) {
376 	dlclose( handler->handle );
377 	handler->handle = NULL;
378 	handler->object = NULL;
379     }
380 
381     /* Finished */
382 
383     return( TRUE );
384 }
385 
386 
ma_GetErrorString(void * x_handler)387 char	*ma_GetErrorString( void *x_handler )
388 {
389     ma_Hand	*handler = x_handler;
390 
391     /* Make sure that the handler is open */
392 
393     if( handler->handle == NULL || handler->object == NULL ||
394 	handler->data == NULL )
395     {
396 	static char	message[512];
397 	sprintf( message, "MEDLINE %s output handler is not open",
398 		handler->handler_name );
399 	return( message );
400     }
401 
402     /* We have the handler - get the error string */
403 
404     return( handler->object->get_error( handler->data ) );
405 }
406