Release 971012
[wine/multimedia.git] / if1632 / builtin.c
blob29ba5accafdbc16461e7e301d8b98db6837adc25
1 /*
2 * Built-in modules
4 * Copyright 1996 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <ctype.h>
9 #include <string.h>
10 #include "windows.h"
11 #include "gdi.h"
12 #include "global.h"
13 #include "heap.h"
14 #include "module.h"
15 #include "miscemu.h"
16 #include "neexe.h"
17 #include "stackframe.h"
18 #include "user.h"
19 #include "stddebug.h"
20 #include "debug.h"
22 /* Built-in modules descriptors */
23 /* Don't change these structures! (see tools/build.c) */
25 typedef struct
27 const char *name; /* DLL name */
28 void *module_start; /* 32-bit address of the module data */
29 int module_size; /* Size of the module data */
30 const BYTE *code_start; /* 32-bit address of DLL code */
31 const BYTE *data_start; /* 32-bit address of DLL data */
32 } WIN16_DESCRIPTOR;
34 typedef struct
36 const char *name; /* DLL name */
37 int base; /* Ordinal base */
38 int nb_funcs; /* Number of functions */
39 int nb_names; /* Number of function names */
40 const void **functions; /* Pointer to function table */
41 const char * const *names; /* Pointer to names table */
42 const WORD *ordinals; /* Pointer to ordinals table */
43 const BYTE *args; /* Pointer to argument lengths */
44 } WIN32_DESCRIPTOR;
46 typedef union
48 const char *name; /* DLL name */
49 WIN16_DESCRIPTOR win16; /* Descriptor for Win16 DLL */
50 WIN32_DESCRIPTOR win32; /* Descriptor for Win32 DLL */
51 } DLL_DESCRIPTOR;
53 typedef struct
55 BYTE call; /* 0xe8 call callfrom32 (relative) */
56 DWORD callfrom32 WINE_PACKED; /* RELAY_CallFrom32 relative addr */
57 BYTE ret; /* 0xc2 ret $n or 0xc3 ret */
58 WORD args; /* nb of args to remove from the stack */
59 } DEBUG_ENTRY_POINT;
61 typedef struct
63 const DLL_DESCRIPTOR *descr; /* DLL descriptor */
64 DEBUG_ENTRY_POINT *dbg_funcs; /* Relay debugging functions table */
65 int flags; /* flags (see below) */
66 } BUILTIN_DLL;
68 /* DLL flags */
69 #define DLL_FLAG_NOT_USED 0x01 /* Use original Windows DLL if possible */
70 #define DLL_FLAG_ALWAYS_USED 0x02 /* Always use built-in DLL */
71 #define DLL_FLAG_WIN32 0x04 /* DLL is a Win32 DLL */
73 /* 16-bit DLLs */
75 extern const DLL_DESCRIPTOR KERNEL_Descriptor;
76 extern const DLL_DESCRIPTOR USER_Descriptor;
77 extern const DLL_DESCRIPTOR GDI_Descriptor;
78 extern const DLL_DESCRIPTOR WIN87EM_Descriptor;
79 extern const DLL_DESCRIPTOR MMSYSTEM_Descriptor;
80 extern const DLL_DESCRIPTOR SHELL_Descriptor;
81 extern const DLL_DESCRIPTOR SOUND_Descriptor;
82 extern const DLL_DESCRIPTOR KEYBOARD_Descriptor;
83 extern const DLL_DESCRIPTOR WINSOCK_Descriptor;
84 extern const DLL_DESCRIPTOR STRESS_Descriptor;
85 extern const DLL_DESCRIPTOR SYSTEM_Descriptor;
86 extern const DLL_DESCRIPTOR TOOLHELP_Descriptor;
87 extern const DLL_DESCRIPTOR MOUSE_Descriptor;
88 extern const DLL_DESCRIPTOR COMMDLG_Descriptor;
89 extern const DLL_DESCRIPTOR OLE2_Descriptor;
90 extern const DLL_DESCRIPTOR OLE2CONV_Descriptor;
91 extern const DLL_DESCRIPTOR OLE2DISP_Descriptor;
92 extern const DLL_DESCRIPTOR OLE2NLS_Descriptor;
93 extern const DLL_DESCRIPTOR OLE2PROX_Descriptor;
94 extern const DLL_DESCRIPTOR OLECLI_Descriptor;
95 extern const DLL_DESCRIPTOR OLESVR_Descriptor;
96 extern const DLL_DESCRIPTOR COMPOBJ_Descriptor;
97 extern const DLL_DESCRIPTOR STORAGE_Descriptor;
98 extern const DLL_DESCRIPTOR WPROCS_Descriptor;
99 extern const DLL_DESCRIPTOR DDEML_Descriptor;
100 extern const DLL_DESCRIPTOR LZEXPAND_Descriptor;
101 extern const DLL_DESCRIPTOR VER_Descriptor;
102 extern const DLL_DESCRIPTOR W32SYS_Descriptor;
103 extern const DLL_DESCRIPTOR WING_Descriptor;
105 /* 32-bit DLLs */
107 extern const DLL_DESCRIPTOR ADVAPI32_Descriptor;
108 extern const DLL_DESCRIPTOR COMCTL32_Descriptor;
109 extern const DLL_DESCRIPTOR COMDLG32_Descriptor;
110 extern const DLL_DESCRIPTOR CRTDLL_Descriptor;
111 extern const DLL_DESCRIPTOR OLE32_Descriptor;
112 extern const DLL_DESCRIPTOR GDI32_Descriptor;
113 extern const DLL_DESCRIPTOR KERNEL32_Descriptor;
114 extern const DLL_DESCRIPTOR LZ32_Descriptor;
115 extern const DLL_DESCRIPTOR MPR_Descriptor;
116 extern const DLL_DESCRIPTOR NTDLL_Descriptor;
117 extern const DLL_DESCRIPTOR SHELL32_Descriptor;
118 extern const DLL_DESCRIPTOR USER32_Descriptor;
119 extern const DLL_DESCRIPTOR VERSION_Descriptor;
120 extern const DLL_DESCRIPTOR WINMM_Descriptor;
121 extern const DLL_DESCRIPTOR WINSPOOL_Descriptor;
122 extern const DLL_DESCRIPTOR WSOCK32_Descriptor;
124 /* Table of all built-in DLLs */
126 static BUILTIN_DLL BuiltinDLLs[] =
128 /* Win16 DLLs */
129 { &KERNEL_Descriptor, NULL, DLL_FLAG_ALWAYS_USED },
130 { &USER_Descriptor, NULL, DLL_FLAG_ALWAYS_USED },
131 { &GDI_Descriptor, NULL, DLL_FLAG_ALWAYS_USED },
132 { &SYSTEM_Descriptor, NULL, DLL_FLAG_ALWAYS_USED },
133 { &WIN87EM_Descriptor, NULL, DLL_FLAG_NOT_USED },
134 { &SHELL_Descriptor, NULL, 0 },
135 { &SOUND_Descriptor, NULL, 0 },
136 { &KEYBOARD_Descriptor, NULL, 0 },
137 { &WINSOCK_Descriptor, NULL, 0 },
138 { &STRESS_Descriptor, NULL, 0 },
139 { &MMSYSTEM_Descriptor, NULL, 0 },
140 { &TOOLHELP_Descriptor, NULL, 0 },
141 { &MOUSE_Descriptor, NULL, 0 },
142 { &COMMDLG_Descriptor, NULL, DLL_FLAG_NOT_USED },
143 { &OLE2_Descriptor, NULL, DLL_FLAG_NOT_USED },
144 { &OLE2CONV_Descriptor, NULL, DLL_FLAG_NOT_USED },
145 { &OLE2DISP_Descriptor, NULL, DLL_FLAG_NOT_USED },
146 { &OLE2NLS_Descriptor, NULL, DLL_FLAG_NOT_USED },
147 { &OLE2PROX_Descriptor, NULL, DLL_FLAG_NOT_USED },
148 { &OLECLI_Descriptor, NULL, DLL_FLAG_NOT_USED },
149 { &OLESVR_Descriptor, NULL, DLL_FLAG_NOT_USED },
150 { &COMPOBJ_Descriptor, NULL, DLL_FLAG_NOT_USED },
151 { &STORAGE_Descriptor, NULL, DLL_FLAG_NOT_USED },
152 { &WPROCS_Descriptor, NULL, DLL_FLAG_ALWAYS_USED },
153 { &DDEML_Descriptor, NULL, DLL_FLAG_NOT_USED },
154 { &LZEXPAND_Descriptor, NULL, 0 },
155 { &VER_Descriptor, NULL, 0 },
156 { &W32SYS_Descriptor, NULL, 0 },
157 { &WING_Descriptor, NULL, 0 },
158 /* Win32 DLLs */
159 { &ADVAPI32_Descriptor, NULL, DLL_FLAG_WIN32 },
160 { &COMCTL32_Descriptor, NULL, DLL_FLAG_WIN32 | DLL_FLAG_NOT_USED },
161 { &COMDLG32_Descriptor, NULL, DLL_FLAG_WIN32 },
162 { &CRTDLL_Descriptor, NULL, DLL_FLAG_WIN32 },
163 { &OLE32_Descriptor, NULL, DLL_FLAG_WIN32 | DLL_FLAG_NOT_USED },
164 { &GDI32_Descriptor, NULL, DLL_FLAG_WIN32 },
165 { &KERNEL32_Descriptor, NULL, DLL_FLAG_WIN32 | DLL_FLAG_ALWAYS_USED },
166 { &LZ32_Descriptor, NULL, DLL_FLAG_WIN32 },
167 { &MPR_Descriptor, NULL, DLL_FLAG_WIN32 | DLL_FLAG_NOT_USED },
168 { &NTDLL_Descriptor, NULL, DLL_FLAG_WIN32 },
169 { &SHELL32_Descriptor, NULL, DLL_FLAG_WIN32 },
170 { &USER32_Descriptor, NULL, DLL_FLAG_WIN32 },
171 { &VERSION_Descriptor, NULL, DLL_FLAG_WIN32 },
172 { &WINMM_Descriptor, NULL, DLL_FLAG_WIN32 },
173 { &WINSPOOL_Descriptor, NULL, DLL_FLAG_WIN32 },
174 { &WSOCK32_Descriptor, NULL, DLL_FLAG_WIN32 },
175 /* Last entry */
176 { NULL, NULL, 0 }
179 /* Ordinal number for interrupt 0 handler in WPROCS.DLL */
180 #define FIRST_INTERRUPT_ORDINAL 100
182 /***********************************************************************
183 * BUILTIN_BuildDebugEntryPoints
185 * Build the table of relay-debugging entry points for a Win32 DLL.
187 static void BUILTIN_BuildDebugEntryPoints( BUILTIN_DLL *dll )
189 int i;
190 DEBUG_ENTRY_POINT *entry;
191 extern void RELAY_CallFrom32();
193 assert( !dll->dbg_funcs );
194 assert( dll->flags & DLL_FLAG_WIN32 );
195 dll->dbg_funcs = HeapAlloc( SystemHeap, 0,
196 dll->descr->win32.nb_funcs * sizeof(DEBUG_ENTRY_POINT) );
197 entry = dll->dbg_funcs;
198 for (i = 0; i < dll->descr->win32.nb_funcs; i++, entry++)
200 BYTE args = dll->descr->win32.args[i];
201 entry->call = 0xe8; /* call */
202 switch(args)
204 case 0xfe: /* register func */
205 entry->callfrom32 = (DWORD)dll->descr->win32.functions[i] -
206 (DWORD)&entry->ret;
207 entry->ret = 0x90; /* nop */
208 entry->args = 0;
209 break;
210 case 0xff: /* stub */
211 entry->args = 0xffff;
212 break;
213 default: /* normal function (stdcall or cdecl) */
214 entry->callfrom32 = (DWORD)RELAY_CallFrom32 - (DWORD)&entry->ret;
215 entry->ret = (args & 0x80) ? 0xc3 : 0xc2; /* ret / ret $n */
216 entry->args = (args & 0x7f) * sizeof(int);
217 break;
223 /***********************************************************************
224 * BUILTIN_DoLoadModule16
226 * Load a built-in Win16 module. Helper function for BUILTIN_LoadModule
227 * and BUILTIN_Init.
229 static HMODULE16 BUILTIN_DoLoadModule16( const WIN16_DESCRIPTOR *descr )
231 NE_MODULE *pModule;
232 int minsize;
233 SEGTABLEENTRY *pSegTable;
235 HMODULE16 hModule = GLOBAL_CreateBlock( GMEM_MOVEABLE, descr->module_start,
236 descr->module_size, 0,
237 FALSE, FALSE, FALSE, NULL );
238 if (!hModule) return 0;
239 FarSetOwner( hModule, hModule );
241 dprintf_module( stddeb, "Built-in %s: hmodule=%04x\n",
242 descr->name, hModule );
243 pModule = (NE_MODULE *)GlobalLock16( hModule );
244 pModule->self = hModule;
246 /* Allocate the code segment */
248 pSegTable = NE_SEG_TABLE( pModule );
249 pSegTable->selector = GLOBAL_CreateBlock( GMEM_FIXED, descr->code_start,
250 pSegTable->minsize, hModule,
251 TRUE, TRUE, FALSE, NULL );
252 if (!pSegTable->selector) return 0;
253 pSegTable++;
255 /* Allocate the data segment */
257 minsize = pSegTable->minsize ? pSegTable->minsize : 0x10000;
258 minsize += pModule->heap_size;
259 if (minsize > 0x10000) minsize = 0x10000;
260 pSegTable->selector = GLOBAL_Alloc( GMEM_FIXED, minsize,
261 hModule, FALSE, FALSE, FALSE );
262 if (!pSegTable->selector) return 0;
263 if (pSegTable->minsize) memcpy( GlobalLock16( pSegTable->selector ),
264 descr->data_start, pSegTable->minsize);
265 if (pModule->heap_size)
266 LocalInit( pSegTable->selector, pSegTable->minsize, minsize );
268 MODULE_RegisterModule( pModule );
269 return hModule;
273 /***********************************************************************
274 * BUILTIN_DoLoadModule32
276 * Load a built-in Win32 module. Helper function for BUILTIN_LoadModule
277 * and BUILTIN_Init.
279 static HMODULE16 BUILTIN_DoLoadModule32( BUILTIN_DLL *table )
281 HMODULE16 hModule;
282 NE_MODULE *pModule;
283 OFSTRUCT ofs;
285 sprintf( ofs.szPathName, "%s.DLL", table->descr->name );
286 hModule = MODULE_CreateDummyModule( &ofs );
287 pModule = (NE_MODULE *)GlobalLock16( hModule );
288 pModule->pe_module = (PE_MODULE *)table;
289 pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN |
290 NE_FFLAGS_LIBMODULE | NE_FFLAGS_WIN32;
291 if (debugging_relay) BUILTIN_BuildDebugEntryPoints( table );
292 return hModule;
296 /***********************************************************************
297 * BUILTIN_Init
299 * Load all built-in modules marked as 'always used'.
301 BOOL32 BUILTIN_Init(void)
303 BUILTIN_DLL *dll;
304 NE_MODULE *pModule;
305 WORD vector;
306 HMODULE16 hModule;
308 for (dll = BuiltinDLLs; dll->descr; dll++)
310 if (!(dll->flags & DLL_FLAG_ALWAYS_USED)) continue;
311 if (dll->flags & DLL_FLAG_WIN32)
313 if (!BUILTIN_DoLoadModule32( dll )) return FALSE;
315 else
317 if (!BUILTIN_DoLoadModule16( &dll->descr->win16 )) return FALSE;
321 /* Set the USER and GDI heap selectors */
323 pModule = MODULE_GetPtr( GetModuleHandle16( "USER" ));
324 USER_HeapSel = (NE_SEG_TABLE( pModule ) + pModule->dgroup - 1)->selector;
325 pModule = MODULE_GetPtr( GetModuleHandle16( "GDI" ));
326 GDI_HeapSel = (NE_SEG_TABLE( pModule ) + pModule->dgroup - 1)->selector;
328 /* Initialize KERNEL.178 (__WINFLAGS) with the correct flags value */
330 hModule = GetModuleHandle16( "KERNEL" );
331 MODULE_SetEntryPoint( hModule, 178, GetWinFlags() );
333 /* Initialize the real-mode selector entry points */
335 DOSMEM_InitExports( hModule );
337 /* Set interrupt vectors from entry points in WPROCS.DLL */
339 hModule = GetModuleHandle16( "WPROCS" );
340 for (vector = 0; vector < 256; vector++)
342 FARPROC16 proc = MODULE_GetEntryPoint( hModule,
343 FIRST_INTERRUPT_ORDINAL+vector);
344 assert(proc);
345 INT_SetHandler( vector, proc );
348 return TRUE;
352 /***********************************************************************
353 * BUILTIN_LoadModule
355 * Load a built-in module. If the 'force' parameter is FALSE, we only
356 * load the module if it has not been disabled via the -dll option.
358 HMODULE16 BUILTIN_LoadModule( LPCSTR name, BOOL32 force )
360 BUILTIN_DLL *table;
361 char dllname[16], *p;
363 /* Fix the name in case we have a full path and extension */
365 if ((p = strrchr( name, '\\' ))) name = p + 1;
366 lstrcpyn32A( dllname, name, sizeof(dllname) );
367 if ((p = strrchr( dllname, '.' ))) *p = '\0';
369 for (table = BuiltinDLLs; table->descr; table++)
370 if (!lstrcmpi32A( table->descr->name, dllname )) break;
371 if (!table->descr) return 0;
372 if ((table->flags & DLL_FLAG_NOT_USED) && !force) return 0;
374 if (table->flags & DLL_FLAG_WIN32)
375 return BUILTIN_DoLoadModule32( table );
376 else
377 return BUILTIN_DoLoadModule16( &table->descr->win16 );
381 /***********************************************************************
382 * BUILTIN_GetEntryPoint16
384 * Return the ordinal and name corresponding to a CS:IP address.
385 * This is used only by relay debugging.
387 LPCSTR BUILTIN_GetEntryPoint16( WORD cs, WORD ip, WORD *pOrd )
389 static char buffer[80];
390 WORD ordinal, i, max_offset;
391 register BYTE *p;
392 NE_MODULE *pModule;
394 if (!(pModule = MODULE_GetPtr( FarGetOwner( GlobalHandle16(cs) ))))
395 return NULL;
397 /* Search for the ordinal */
399 p = (BYTE *)pModule + pModule->entry_table;
400 max_offset = 0;
401 ordinal = 1;
402 *pOrd = 0;
403 while (*p)
405 switch(p[1])
407 case 0: /* unused */
408 ordinal += *p;
409 p += 2;
410 break;
411 case 1: /* code segment */
412 i = *p;
413 p += 2;
414 while (i-- > 0)
416 p++;
417 if ((*(WORD *)p <= ip) && (*(WORD *)p >= max_offset))
419 max_offset = *(WORD *)p;
420 *pOrd = ordinal;
422 p += 2;
423 ordinal++;
425 break;
426 case 0xff: /* moveable (should not happen in built-in modules) */
427 fprintf( stderr, "Built-in module has moveable entry\n" );
428 ordinal += *p;
429 p += 2 + *p * 6;
430 break;
431 default: /* other segment */
432 ordinal += *p;
433 p += 2 + *p * 3;
434 break;
438 /* Search for the name in the resident names table */
439 /* (built-in modules have no non-resident table) */
441 p = (BYTE *)pModule + pModule->name_table;
442 while (*p)
444 p += *p + 1 + sizeof(WORD);
445 if (*(WORD *)(p + *p + 1) == *pOrd) break;
448 sprintf( buffer, "%.*s.%d: %.*s",
449 *((BYTE *)pModule + pModule->name_table),
450 (char *)pModule + pModule->name_table + 1,
451 *pOrd, *p, (char *)(p + 1) );
452 return buffer;
456 /***********************************************************************
457 * BUILTIN_GetEntryPoint32
459 * Return the name of the DLL entry point corresponding
460 * to a relay entry point address. This is used only by relay debugging.
462 * This function _must_ return the real entry point to call
463 * after the debug info is printed.
465 FARPROC32 BUILTIN_GetEntryPoint32( char *buffer, void *relay )
467 BUILTIN_DLL *dll;
468 int ordinal, i;
469 const WIN32_DESCRIPTOR *descr;
471 /* First find the module */
473 for (dll = BuiltinDLLs; dll->descr; dll++)
474 if ((dll->flags & DLL_FLAG_WIN32) &&
475 ((void *)dll->dbg_funcs <= relay) &&
476 ((void *)(dll->dbg_funcs + dll->descr->win32.nb_funcs) > relay))
477 break;
478 assert(dll->descr);
479 descr = &dll->descr->win32;
481 /* Now find the function */
483 ordinal = ((DWORD)relay-(DWORD)dll->dbg_funcs) / sizeof(DEBUG_ENTRY_POINT);
484 ordinal += descr->base;
485 for (i = 0; i < descr->nb_names; i++)
486 if (descr->ordinals[i] == ordinal) break;
487 assert( i < descr->nb_names );
489 sprintf( buffer, "%s.%d: %s", descr->name, ordinal, descr->names[i] );
490 return (FARPROC32)descr->functions[ordinal - descr->base];
494 /***********************************************************************
495 * BUILTIN_GetProcAddress32
497 * Implementation of GetProcAddress() for built-in Win32 modules.
498 * FIXME: this should be unified with the real GetProcAddress32().
500 FARPROC32 BUILTIN_GetProcAddress32( NE_MODULE *pModule, LPCSTR function )
502 BUILTIN_DLL *dll = (BUILTIN_DLL *)pModule->pe_module;
503 const WIN32_DESCRIPTOR *info = &dll->descr->win32;
504 WORD ordinal = 0;
506 if (!dll) return NULL;
508 if (HIWORD(function)) /* Find function by name */
510 int i;
512 dprintf_module( stddeb, "Looking for function %s in %s\n",
513 function, dll->descr->name );
514 for (i = 0; i < info->nb_names; i++)
515 if (!strcmp( function, info->names[i] ))
517 ordinal = info->ordinals[i];
518 break;
520 if (i >= info->nb_names) return NULL; /* not found */
522 else /* Find function by ordinal */
524 ordinal = LOWORD(function);
525 dprintf_module( stddeb, "Looking for ordinal %d in %s\n",
526 ordinal, dll->descr->name );
527 if ((ordinal < info->base) || (ordinal >= info->base + info->nb_funcs))
528 return NULL; /* not found */
530 if (dll->dbg_funcs && (dll->dbg_funcs[ordinal-info->base].args != 0xffff))
531 return (FARPROC32)&dll->dbg_funcs[ordinal - info->base];
532 return (FARPROC32)info->functions[ordinal - info->base];
536 /**********************************************************************
537 * BUILTIN_DefaultIntHandler
539 * Default interrupt handler.
541 void BUILTIN_DefaultIntHandler( CONTEXT *context )
543 WORD ordinal;
544 STACK16FRAME *frame = CURRENT_STACK16;
545 BUILTIN_GetEntryPoint16( frame->entry_cs, frame->entry_ip, &ordinal );
546 INT_BARF( context, ordinal - FIRST_INTERRUPT_ORDINAL );
550 /***********************************************************************
551 * BUILTIN_ParseDLLOptions
553 * Set runtime DLL usage flags
555 BOOL32 BUILTIN_ParseDLLOptions( const char *str )
557 BUILTIN_DLL *dll;
558 const char *p;
560 while (*str)
562 while (*str && isspace(*str)) str++;
563 if (!*str) return TRUE;
564 if ((*str != '+') && (*str != '-')) return FALSE;
565 str++;
566 if (!(p = strchr( str, ',' ))) p = str + strlen(str);
567 while ((p > str) && isspace(p[-1])) p--;
568 if (p == str) return FALSE;
569 for (dll = BuiltinDLLs; dll->descr; dll++)
571 if (!lstrncmpi32A( str, dll->descr->name, (int)(p - str) ))
573 if (str[-1] == '-')
575 if (dll->flags & DLL_FLAG_ALWAYS_USED) return FALSE;
576 dll->flags |= DLL_FLAG_NOT_USED;
578 else dll->flags &= ~DLL_FLAG_NOT_USED;
579 break;
582 if (!dll->descr) return FALSE;
583 str = p;
584 while (*str && (isspace(*str) || (*str == ','))) str++;
586 return TRUE;
590 /***********************************************************************
591 * BUILTIN_PrintDLLs
593 * Print the list of built-in DLLs that can be disabled.
595 void BUILTIN_PrintDLLs(void)
597 int i;
598 BUILTIN_DLL *dll;
600 for (i = 0, dll = BuiltinDLLs; dll->descr; dll++)
602 if (!(dll->flags & DLL_FLAG_ALWAYS_USED))
603 fprintf( stderr, "%-9s%c", dll->descr->name,
604 ((++i) % 8) ? ' ' : '\n' );
606 fprintf(stderr,"\n");
607 exit(1);