moving Tcl stuff around slightly.
[fw/openocd] / src / openocd.c
1 /***************************************************************************
2  *   Copyright (C) 2005 by Dominic Rath                                    *
3  *   Dominic.Rath@gmx.de                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #define OPENOCD_VERSION "Open On-Chip Debugger " VERSION " (" PKGBLDDATE ") svn:" PKGBLDREV
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "log.h"
28 #include "types.h"
29 #include "jtag.h"
30 #include "configuration.h"
31 #include "interpreter.h"
32 #include "xsvf.h"
33 #include "target.h"
34 #include "flash.h"
35 #include "nand.h"
36 #include "pld.h"
37
38 #include "command.h"
39 #include "server.h"
40 #include "telnet_server.h"
41 #include "gdb_server.h"
42 #include "tcl_server.h"
43
44 #include <sys/time.h>
45 #include <sys/types.h>
46 #include <strings.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <errno.h>
52
53 #ifdef __ECOS
54 /* Jim is provied by eCos */
55 #include <cyg/jimtcl/jim.h>
56 #else
57 #define JIM_EMBEDDED
58 #include "jim.h"
59 #endif
60
61
62
63
64 int launchTarget(struct command_context_s *cmd_ctx)
65 {
66         int retval;
67         /* Try to examine & validate jtag chain, though this may require a reset first
68          * in which case we continue setup */
69         jtag_init(cmd_ctx);
70
71         /* try to examine target at this point. If it fails, perhaps a reset will
72          * bring it up later on via a telnet/gdb session */
73         target_examine(cmd_ctx);
74
75         retval=flash_init_drivers(cmd_ctx);
76         if (retval!=ERROR_OK)
77                 return retval;
78         LOG_DEBUG("flash init complete");
79
80         retval=nand_init(cmd_ctx);
81         if (retval!=ERROR_OK)
82                 return retval;
83         LOG_DEBUG("NAND init complete");
84
85         retval=pld_init(cmd_ctx);
86         if (retval!=ERROR_OK)
87                 return retval;
88         LOG_DEBUG("pld init complete");
89         return retval;
90 }
91
92 /* Give TELNET a way to find out what version this is */
93 int handle_version_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
94 {
95         command_print(cmd_ctx, OPENOCD_VERSION);
96
97         return ERROR_OK;
98 }
99
100 static int daemon_startup = 0;
101
102 int handle_daemon_startup_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
103 {
104         if (argc==0)
105                 return ERROR_OK;
106         if (argc > 1 )
107                 return ERROR_COMMAND_SYNTAX_ERROR;
108         
109         daemon_startup = strcmp("reset", args[0])==0;
110         
111         command_print(cmd_ctx, OPENOCD_VERSION);
112
113         return ERROR_OK;
114 }
115
116
117 void exit_handler(void)
118 {
119         /* close JTAG interface */
120         if (jtag && jtag->quit)
121                 jtag->quit();
122 }
123
124
125 /* OpenOCD can't really handle failure of this command. Patches welcome! :-) */
126 int handle_init_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
127 {
128         int retval;
129         static int initialized=0;
130         if (initialized)
131                 return ERROR_OK;
132         
133         initialized=1;
134         
135         command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
136
137         atexit(exit_handler);
138
139         
140         if (target_init(cmd_ctx) != ERROR_OK)
141                 return ERROR_FAIL;
142         LOG_DEBUG("target init complete");
143
144         if ((retval=jtag_interface_init(cmd_ctx)) != ERROR_OK)
145         {
146                 /* we must be able to set up the jtag interface */
147                 return retval;
148         }
149         LOG_DEBUG("jtag interface init complete");
150
151         /* Try to initialize & examine the JTAG chain at this point, but
152          * continue startup regardless
153          */
154         if (jtag_init(cmd_ctx) == ERROR_OK)
155         {
156                 LOG_DEBUG("jtag init complete");
157                 if (target_examine(cmd_ctx) == ERROR_OK)
158                 {
159                         LOG_DEBUG("jtag examine complete");
160                 }
161         }
162
163         
164         if (flash_init_drivers(cmd_ctx) != ERROR_OK)
165                 return ERROR_FAIL;
166         LOG_DEBUG("flash init complete");
167
168         if (nand_init(cmd_ctx) != ERROR_OK)
169                 return ERROR_FAIL;
170         LOG_DEBUG("NAND init complete");
171
172         if (pld_init(cmd_ctx) != ERROR_OK)
173                 return ERROR_FAIL;
174         LOG_DEBUG("pld init complete");
175
176         /* initialize tcp server */
177         server_init();
178
179         /* initialize telnet subsystem */
180         telnet_init("Open On-Chip Debugger");
181         gdb_init();
182         tcl_init(); /* allows tcl to just connect without going thru telnet */
183
184         return ERROR_OK;
185 }
186
187
188 void lockBigLock();
189 void unlockBigLock();
190
191
192
193 Jim_Interp *interp;
194 command_context_t *active_cmd_ctx;
195
196 static int
197 new_int_array_element( Jim_Interp * interp, 
198                                            const char *varname, 
199                                            int idx, 
200                                            u32 val )
201 {
202         char *namebuf;
203         Jim_Obj *nameObjPtr, *valObjPtr;
204         int result;
205
206         namebuf = alloc_printf("%s(%d)", varname, idx );
207
208
209     nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
210     valObjPtr = Jim_NewIntObj(interp, val );
211     Jim_IncrRefCount(nameObjPtr);
212     Jim_IncrRefCount(valObjPtr);
213     result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
214     Jim_DecrRefCount(interp, nameObjPtr);
215     Jim_DecrRefCount(interp, valObjPtr);
216     free(namebuf);
217         // printf( "%s = 0%08x\n", namebuf, val );
218     return result;
219 }
220
221 static int
222 Jim_Command_mem2array( Jim_Interp *interp, int argc, Jim_Obj *const *argv)
223 {
224         target_t *target;
225         long l;
226         u32 width;
227         u32 len;
228         u32 addr;
229         u32 count;
230         u32 v;
231         const char *varname;
232         u8 buffer[4096];
233         int  i,n,e,retval;
234
235
236         /* argv[1] = name of array to receive the data
237          * argv[2] = desired width
238          * argv[3] = memory address 
239          * argv[4] = length in bytes to read
240          */
241         if( argc != 5 ){
242                 Jim_WrongNumArgs( interp, 1, argv, "varname width addr nelems" );
243                 return JIM_ERR;
244         }
245         varname = Jim_GetString( argv[1], &len );
246         /* given "foo" get space for worse case "foo(%d)" .. add 20 */
247
248
249         e = Jim_GetLong( interp, argv[2], &l );
250         width = l;
251         if( e != JIM_OK ){
252                 return e;
253         }
254         
255         e = Jim_GetLong( interp, argv[3], &l );
256         addr = l;
257         if( e != JIM_OK ){
258                 return e;
259         }
260         e = Jim_GetLong( interp, argv[4], &l );
261         len = l;
262         if( e != JIM_OK ){
263                 return e;
264         }
265         switch(width){
266         case 8:
267                 width = 1;
268                 break;
269         case 16:
270                 width = 2;
271                 break;
272         case 32:
273                 width = 4;
274                 break;
275         default:
276                 Jim_SetResult(interp, 
277                                           Jim_NewEmptyStringObj(interp));
278                 Jim_AppendStrings( interp, Jim_GetResult(interp),
279                                                    "Invalid width param, must be 8/16/32", NULL );
280                 return JIM_ERR;
281         }
282         if( len == 0 ){
283                 Jim_SetResult(interp, 
284                                           Jim_NewEmptyStringObj(interp));
285                 Jim_AppendStrings( interp, Jim_GetResult(interp),
286                                                    "mem2array: zero width read?", NULL );
287                 return JIM_ERR;
288         }
289         if( (addr + (len * width)) < addr ){
290                 Jim_SetResult(interp, 
291                                           Jim_NewEmptyStringObj(interp));
292                 Jim_AppendStrings( interp, Jim_GetResult(interp),
293                                                    "mem2array: addr + len - wraps to zero?", NULL );
294                 return JIM_ERR;
295         }
296         /* absurd transfer size? */
297         if( len > 65536 ){
298                 Jim_SetResult(interp, 
299                                           Jim_NewEmptyStringObj(interp));
300                 Jim_AppendStrings( interp, Jim_GetResult(interp),
301                                                    "mem2array: absurd > 64K item request", NULL );
302                 return JIM_ERR;
303         }               
304                 
305         if( (width == 1) ||
306                 ((width == 2) && ((addr & 1) == 0)) ||
307                 ((width == 4) && ((addr & 3) == 0)) ){
308                 /* all is well */
309         } else {
310                 char buf[100];
311                 Jim_SetResult(interp, 
312                                           Jim_NewEmptyStringObj(interp));
313                 sprintf( buf, 
314                                  "mem2array address: 0x%08x is not aligned for %d byte reads",
315                                  addr, width );
316                                  
317                 Jim_AppendStrings( interp, Jim_GetResult(interp),
318                                                    buf , NULL );
319                 return JIM_ERR;
320         }
321
322         target = get_current_target( active_cmd_ctx );
323         
324         /* Transfer loop */
325
326         /* index counter */
327         n = 0;
328         /* assume ok */
329         e = JIM_OK;
330         while( len ){
331
332                 /* Slurp... in buffer size chunks */
333                 
334                 count = len; /* in objects.. */
335                 if( count > (sizeof(buffer)/width)){
336                         count = (sizeof(buffer)/width);
337                 }
338                 
339                 retval = target->type->read_memory( target, 
340                                                                                         addr, 
341                                                                                         width, 
342                                                                                         count,
343                                                                                         buffer );
344
345                 if( retval != ERROR_OK ){
346                         /* BOO !*/
347                         LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed",
348                                           addr, width, count );
349                         Jim_SetResult(interp, 
350                                                   Jim_NewEmptyStringObj(interp));
351                         Jim_AppendStrings( interp, Jim_GetResult(interp),
352                                                    "mem2array: cannot read memory", NULL );
353                         e = JIM_ERR;
354                         len = 0;
355                 } else {
356                         v = 0; /* shut up gcc */
357                         for( i = 0 ; i < count ; i++, n++ ){
358                                 switch(width){
359                                 case 4:
360                                         v = target_buffer_get_u32( target, &buffer[i*width] );
361                                         break;
362                                 case 2:
363                                         v = target_buffer_get_u16( target, &buffer[i*width] );
364                                         break;
365                                 case 1:
366                                         v = buffer[i] & 0x0ff;
367                                         break;
368                                 }
369                                 new_int_array_element( interp, varname, n, v );
370                         }
371                         len -= count;
372                 }
373         }
374         Jim_SetResult(interp, 
375                                   Jim_NewEmptyStringObj(interp));
376
377         return JIM_OK;
378 }
379
380 static void tcl_output(void *privData, const char *file, int line, 
381                 const char *function, const char *string)
382 {               
383         Jim_Obj *tclOutput=(Jim_Obj *)privData;
384
385         Jim_AppendString(interp, tclOutput, string, strlen(string));
386 }
387
388 /* try to execute as Jim command, otherwise fall back to standard command.
389
390         Note that even if the Jim command caused an error, then we succeeded
391         to execute it, hence this fn pretty much always returns ERROR_OK. 
392
393  */
394 int jim_command(command_context_t *context, char *line)
395 {
396         int retval=ERROR_OK;
397         /* FIX!!!! in reality there is only one cmd_ctx handler, but consider
398         what might happen here if there are multiple handlers w/reentrant callback
399         fn's... shudder!  */
400         active_cmd_ctx=context;
401         int retcode=Jim_Eval(interp, line);
402         
403         const char *result;
404         int reslen;
405     result = Jim_GetString(Jim_GetResult(interp), &reslen);
406     if (retcode == JIM_ERR) {
407             int len, i;
408         
409             LOG_USER_N("Runtime error, file \"%s\", line %d:" JIM_NL,
410                     interp->errorFileName, interp->errorLine);
411             LOG_USER_N("    %s" JIM_NL,
412                     Jim_GetString(interp->result, NULL));
413             Jim_ListLength(interp, interp->stackTrace, &len);
414             for (i = 0; i < len; i+= 3) {
415                 Jim_Obj *objPtr;
416                 const char *proc, *file, *line;
417         
418                 Jim_ListIndex(interp, interp->stackTrace, i, &objPtr, JIM_NONE);
419                 proc = Jim_GetString(objPtr, NULL);
420                 Jim_ListIndex(interp, interp->stackTrace, i+1, &objPtr,
421                         JIM_NONE);
422                 file = Jim_GetString(objPtr, NULL);
423                 Jim_ListIndex(interp, interp->stackTrace, i+2, &objPtr,
424                         JIM_NONE);
425                 line = Jim_GetString(objPtr, NULL);
426                 LOG_USER_N("In procedure '%s' called at file \"%s\", line %s" JIM_NL,
427                         proc, file, line);
428             }
429     } else if (retcode == JIM_EXIT) {
430         // ignore.
431         //exit(Jim_GetExitCode(interp));
432     } else {
433         if (reslen) {
434                 int i;
435                 char buff[256+1];
436                 for (i=0; i<reslen; i+=256)
437                 {
438                         int chunk;
439                         chunk=reslen-i;
440                         if (chunk>256)
441                                 chunk=256;
442                         strncpy(buff, result, chunk);
443                         buff[chunk]=0; 
444                 LOG_USER_N("%s", buff);
445                 }
446                 LOG_USER_N("%s", "\n");
447         }
448     }
449         return retval;
450 }
451
452 int startLoop=0;
453
454 static int
455 Jim_Command_openocd_ignore(Jim_Interp *interp, 
456                                    int argc,
457                                    Jim_Obj *const *argv,
458                                    int ignore)
459 {
460         int retval;
461     char *cmd = (char*)Jim_GetString(argv[1], NULL);
462
463         lockBigLock();
464         
465     Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
466     
467     if (startLoop)
468     {
469         // We don't know whether or not the telnet/gdb server is running...
470         target_call_timer_callbacks_now();
471     }
472         
473         log_add_callback(tcl_output, tclOutput);
474     retval=command_run_line_internal(active_cmd_ctx, cmd);
475     
476     if (startLoop)
477     {
478         target_call_timer_callbacks_now();
479     }
480         log_remove_callback(tcl_output, tclOutput);
481     
482         Jim_SetResult(interp, tclOutput);
483     unlockBigLock();
484         
485     return (ignore||(retval==ERROR_OK))?JIM_OK:JIM_ERR;
486 }
487
488 static int
489 Jim_Command_openocd(Jim_Interp *interp, 
490                                    int argc,
491                                    Jim_Obj *const *argv)
492 {
493         return Jim_Command_openocd_ignore(interp, argc, argv, 1); 
494 }
495
496 static int
497 Jim_Command_openocd_throw(Jim_Interp *interp, 
498                                    int argc,
499                                    Jim_Obj *const *argv)
500 {
501         return Jim_Command_openocd_ignore(interp, argc, argv, 0); 
502 }
503   
504
505
506
507 /* find full path to file */
508 static int
509 Jim_Command_find(Jim_Interp *interp, 
510                                    int argc,
511                                    Jim_Obj *const *argv)
512 {
513         if (argc!=2)
514                 return JIM_ERR;
515         char *file = (char*)Jim_GetString(argv[1], NULL);
516         char *full_path=find_file(file);
517         if (full_path==NULL)
518                 return JIM_ERR;
519     Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path));
520     free(full_path);
521     
522         Jim_SetResult(interp, result);
523         return JIM_OK;
524 }
525
526 static int
527 Jim_Command_echo(Jim_Interp *interp, 
528                                    int argc,
529                                    Jim_Obj *const *argv)
530 {
531         if (argc!=2)
532                 return JIM_ERR;
533         char *str = (char*)Jim_GetString(argv[1], NULL);
534         LOG_USER("%s", str);
535         return JIM_OK;
536 }
537
538 void command_output_text( command_context_t *context, const char *data );
539
540 static size_t
541 openocd_jim_fwrite( const void *_ptr, size_t size, size_t n, void *cookie )
542 {
543         size_t nbytes;
544         const char *ptr;
545
546         /* make it a char easier to read code */
547         ptr = _ptr;
548
549         nbytes = size * n;
550         if( nbytes == 0 ){
551                 return 0;
552         }
553
554         if( !active_cmd_ctx ){
555                 /* FIXME: Where should this go? */              
556                 return n;
557         }
558
559         
560         /* do we have to chunk it? */
561         if( ptr[ nbytes ] == 0 ){
562                 /* no it is a C style string */
563                 command_output_text( active_cmd_ctx, ptr );
564                 return strlen(ptr);
565         }
566         /* GRR we must chunk - not null terminated */
567         while( nbytes ){
568                 char chunk[128+1];
569                 int x;
570
571                 x = nbytes;
572                 if( x > 128 ){
573                         x = 128;
574                 }
575                 /* copy it */
576                 memcpy( chunk, ptr, x );
577                 /* terminate it */
578                 chunk[n] = 0;
579                 /* output it */
580                 command_output_text( active_cmd_ctx, chunk );
581                 ptr += x;
582                 nbytes -= x;
583         }
584         
585         return n;
586 }
587
588 static size_t
589 openocd_jim_fread(void *ptr, size_t size, size_t n, void *cookie )
590 {
591         /* TCL wants to read... tell him no */
592         return 0;
593 }
594
595
596 static int
597 openocd_jim_vfprintf( void *cookie, const char *fmt, va_list ap )
598 {
599         char *cp;
600         int n;
601         
602         n = -1;
603         if( active_cmd_ctx ){
604                 cp = alloc_vprintf( fmt, ap );
605                 if( cp ){
606                         command_output_text( active_cmd_ctx, cp );
607                         n = strlen(cp);
608                         free(cp);
609                 }
610         }
611         return n;
612 }
613
614 static int
615 openocd_jim_fflush( void *cookie )
616 {
617         /* nothing to flush */
618         return 0;
619 }
620
621 static char  *
622 openocd_jim_fgets( char *s, int size, void *cookie )
623 {
624         /* not supported */
625         errno = ENOTSUP;
626         return NULL;
627 }
628
629
630
631 void initJim(void)
632 {
633     Jim_CreateCommand(interp, "openocd", Jim_Command_openocd, NULL, NULL);
634     Jim_CreateCommand(interp, "openocd_throw", Jim_Command_openocd_throw, NULL, NULL);
635     Jim_CreateCommand(interp, "find", Jim_Command_find, NULL, NULL);
636     Jim_CreateCommand(interp, "echo", Jim_Command_echo, NULL, NULL);
637     Jim_CreateCommand(interp, "mem2array", Jim_Command_mem2array, NULL, NULL );
638
639         /* Set Jim's STDIO */
640         interp->cookie_stdin  = NULL;
641         interp->cookie_stdout = NULL;
642         interp->cookie_stderr = NULL;
643         interp->cb_fwrite     = openocd_jim_fwrite;
644         interp->cb_fread      = openocd_jim_fread ;
645         interp->cb_vfprintf   = openocd_jim_vfprintf;
646         interp->cb_fflush     = openocd_jim_fflush;
647         interp->cb_fgets      = openocd_jim_fgets;
648 }
649
650 /* after command line parsing */
651 void initJim2(void)
652 {
653         Jim_Eval(interp, "source [find tcl/commands.tcl]");
654 }
655
656 command_context_t *setup_command_handler()
657 {
658         command_context_t *cmd_ctx;
659         
660         cmd_ctx = command_init();
661
662         register_command(cmd_ctx, NULL, "version", handle_version_command,
663                                          COMMAND_EXEC, "show OpenOCD version");
664         register_command(cmd_ctx, NULL, "daemon_startup", handle_daemon_startup_command, COMMAND_CONFIG, 
665                         "deprecated - use \"init\" and \"reset\" at end of startup script instead");
666         
667         /* register subsystem commands */
668         server_register_commands(cmd_ctx);
669         telnet_register_commands(cmd_ctx);
670         gdb_register_commands(cmd_ctx);
671         tcl_register_commands(cmd_ctx); /* tcl server commands */
672         log_register_commands(cmd_ctx);
673         jtag_register_commands(cmd_ctx);
674         interpreter_register_commands(cmd_ctx);
675         xsvf_register_commands(cmd_ctx);
676         target_register_commands(cmd_ctx);
677         flash_register_commands(cmd_ctx);
678         nand_register_commands(cmd_ctx);
679         pld_register_commands(cmd_ctx);
680         
681         if (log_init(cmd_ctx) != ERROR_OK)
682         {
683                 exit(-1);
684         }
685         LOG_DEBUG("log init complete");
686
687         LOG_OUTPUT( OPENOCD_VERSION "\n" );
688         
689         
690         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
691         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
692         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
693         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
694         /* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
695         LOG_OUTPUT( "$URL$\n");
696         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
697         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
698         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
699         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
700         /* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
701
702         register_command(cmd_ctx, NULL, "init", handle_init_command,
703                                          COMMAND_ANY, "initializes target and servers - nop on subsequent invocations");
704
705         return cmd_ctx;
706 }
707
708 /*
709 normally this is the main() function entry, but if OpenOCD is linked
710 into application, then this fn will not be invoked, but rather that
711 application will have it's own implementation of main().
712 */
713 int openocd_main(int argc, char *argv[])
714 {
715 #ifdef JIM_EMBEDDED
716         Jim_InitEmbedded();
717     /* Create an interpreter */
718     interp = Jim_CreateInterp();
719     /* Add all the Jim core commands */
720     Jim_RegisterCoreCommands(interp);
721 #endif
722     
723         initJim();
724         
725         /* initialize commandline interface */
726         command_context_t *cmd_ctx;
727         cmd_ctx=setup_command_handler();
728         
729         command_context_t *cfg_cmd_ctx;
730         cfg_cmd_ctx = copy_command_context(cmd_ctx);
731         cfg_cmd_ctx->mode = COMMAND_CONFIG;
732         command_set_output_handler(cfg_cmd_ctx, configuration_output_handler, NULL);
733         
734         if (parse_cmdline_args(cfg_cmd_ctx, argc, argv) != ERROR_OK)
735                 return EXIT_FAILURE;
736
737         initJim2();
738
739         if (parse_config_file(cfg_cmd_ctx) != ERROR_OK)
740                 return EXIT_FAILURE;
741         
742         command_done(cfg_cmd_ctx);
743
744         if (command_run_line(cmd_ctx, "init")!=ERROR_OK)
745                 return EXIT_FAILURE;
746         
747         if (daemon_startup)
748                 command_run_line(cmd_ctx, "reset");
749
750
751         startLoop=1;
752
753         /* handle network connections */
754         server_loop(cmd_ctx);
755
756         /* shut server down */
757         server_quit();
758
759         unregister_all_commands(cmd_ctx);
760         
761         /* free commandline interface */
762         command_done(cmd_ctx);
763
764         return EXIT_SUCCESS;
765 }
766
767
768 /*
769  * Local Variables: **
770  * tab-width: 4 **
771  * c-basic-offset: 4 **
772  * End: **
773  */
774