OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [libgui/] [src/] [tclhelp.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/* tclhelp.c -- TCL interface to help.
2
   Copyright (C) 1997 Cygnus Solutions.
3
   Written by Ian Lance Taylor <ian@cygnus.com>.  */
4
 
5
#include "config.h"
6
 
7
#include <stdio.h>
8
#include <ctype.h>
9
 
10
#ifdef HAVE_STDLIB_H
11
#include <stdlib.h>
12
#endif
13
 
14
#include <errno.h>
15
#ifndef errno
16
extern int errno;
17
#endif
18
 
19
#ifdef HAVE_STRING_H
20
#include <string.h>
21
#else
22
#ifdef HAVE_STRINGS_H
23
#include <strings.h>
24
#else
25
extern char *strerror ();
26
#endif
27
#endif
28
 
29
#ifdef _WIN32
30
/* We avoid warnings by including this before tcl.h.  */
31
#include <windows.h>
32
#include <winuser.h>
33
#endif
34
 
35
#include <tcl.h>
36
#include <tk.h>
37
 
38
#include "guitcl.h"
39
#include "subcommand.h"
40
 
41
/* This file defines one TCL command with subcommands.  This command
42
   may be used to bring up a help window.
43
 
44
   ide_help initialize ...
45
       Initialize the help system.
46
 
47
       On Windows, this takes two arguments: the name of the help
48
       file, and the name of the header file which may be used to map
49
       help topics to numbers.  This header files is created by the
50
       help system.
51
 
52
       The Unix help system has not yet been implemented.
53
 
54
   ide_help topic TOPIC
55
       Brings up a help window for the particular topic.  The topic is
56
       a string.
57
 
58
   ide_help toc
59
       Brings up a help window for the main table of contents.
60
 
61
   ide_help display_file FILENAME TOPIC_ID
62
       The "display_file" subcommand was added as a hack to get the Foundry Tour to
63
       launch.  The help system can't handle more than one help file and should
64
       be rewritten */
65
 
66
#ifdef _WIN32
67
 
68
/* Windows implementation.  This uses WinHelp.  */
69
 
70
/* We use an instance of this structure as the client data for the
71
   ide_help command.  */
72
 
73
struct help_command_data
74
{
75
  /* The name of the help file.  */
76
  char *filename;
77
  /* The name of the help header file which we use to map topic
78
     strings to numbers.  */
79
  char *header_filename;
80
  /* A hash table mapping help topic strings to numbers.  */
81
  Tcl_HashTable topic_hash;
82
  /* Nonzero if the hash table has been initialized.  */
83
  int hash_initialized;
84
  /* The window we are passing to WinHelp.  */
85
  HWND window;
86
};
87
 
88
/* This function is called as an exit handler.  */
89
 
90
static void
91
help_command_atexit (ClientData cd)
92
{
93
  struct help_command_data *hdata = (struct help_command_data *) cd;
94
 
95
  /* Tell Windows we don't need any more help.  */
96
  if (hdata->window != NULL)
97
    WinHelp (hdata->window, hdata->filename, HELP_QUIT, 0);
98
}
99
 
100
/* This function is called if the ide_help command is deleted.  */
101
 
102
static void
103
help_command_deleted (ClientData cd)
104
{
105
  struct help_command_data *hdata = (struct help_command_data *) cd;
106
 
107
  /* Run the exit handler now, rather than when we exit.  */
108
  help_command_atexit (cd);
109
  Tcl_DeleteExitHandler (help_command_atexit, cd);
110
 
111
  if (hdata->filename != NULL)
112
    free (hdata->filename);
113
  if (hdata->header_filename != NULL)
114
    free (hdata->header_filename);
115
  if (hdata->hash_initialized)
116
    Tcl_DeleteHashTable (&hdata->topic_hash);
117
  Tcl_Free ((char *) hdata);
118
}
119
 
120
/* Initialize the help system: choose a window, and set up the topic
121
   hash table.  We don't set up the topic hash table when the command
122
   is created, because there's no point wasting time on it at program
123
   startup time if the help system is not going to be used.  */
124
 
125
static int
126
help_initialize (Tcl_Interp *interp, struct help_command_data *hdata)
127
{
128
  if (hdata->filename == NULL || hdata->header_filename == NULL)
129
    {
130
      Tcl_SetResult (interp, "help system has not been initialized",
131
                     TCL_STATIC);
132
      return TCL_ERROR;
133
    }
134
 
135
  if (hdata->window == NULL)
136
    {
137
      HWND window, parent;
138
 
139
      /* We don't really care what window we use, although it should
140
         probably be one that will last until the application exits.  */
141
      window = GetActiveWindow ();
142
      if (window == NULL)
143
        window = GetFocus ();
144
      if (window == NULL)
145
        {
146
          Tcl_SetResult (interp, "can't find window to use for help",
147
                         TCL_STATIC);
148
          return TCL_ERROR;
149
        }
150
 
151
      while ((parent = GetParent (window)) != NULL)
152
        window = parent;
153
 
154
      hdata->window = window;
155
 
156
      Tcl_CreateExitHandler (help_command_atexit, (ClientData) hdata);
157
    }
158
 
159
  if (! hdata->hash_initialized)
160
    {
161
      FILE *e;
162
      char buf[200];
163
 
164
      e = fopen (hdata->header_filename, "r");
165
      if (e == NULL)
166
        {
167
          Tcl_AppendResult (interp, "can't open help file \"",
168
                            hdata->header_filename, "\": ",
169
                            strerror (errno), (char *) NULL);
170
          return TCL_ERROR;
171
        }
172
 
173
      Tcl_InitHashTable (&hdata->topic_hash, TCL_STRING_KEYS);
174
      hdata->hash_initialized = 1;
175
 
176
      /* We expect the format of the header file to be tightly
177
         constrained: the lines of interest will look like
178
             #define TOPIC_STRING TOPIC_NUMBER
179
         We ignore all other lines.  We assume that topic strings have
180
         a limited length, since they are created by humans, so for
181
         simplicity we use fgets with a fixed size buffer.  The error
182
         checking is minimal, but that's OK, because this file is part
183
         of the application; it is not created by the user.  */
184
 
185
      while (fgets (buf, sizeof buf, e) != NULL)
186
        {
187
          char *s, *topic;
188
          int number;
189
          Tcl_HashEntry *he;
190
          int new;
191
 
192
          if (strncmp (buf, "#define", 7) != 0)
193
            continue;
194
 
195
          s = buf + 7;
196
          while (isspace ((unsigned char) *s))
197
            ++s;
198
          topic = s;
199
          while (! isspace ((unsigned char) *s))
200
            ++s;
201
          *s = '\0';
202
 
203
          number = atoi (s + 1);
204
          if (number == 0)
205
            continue;
206
 
207
          he = Tcl_CreateHashEntry (&hdata->topic_hash, topic, &new);
208
          Tcl_SetHashValue (he, (ClientData) number);
209
        }
210
 
211
      fclose (e);
212
    }
213
 
214
  return TCL_OK;
215
}
216
 
217
/* Implement the ide_help initialize command.  We don't actually look
218
   at the files now; we only do that if the user requests help.  */
219
 
220
static int
221
help_initialize_command (ClientData cd, Tcl_Interp *interp, int argc,
222
                         char **argv)
223
{
224
  struct help_command_data *hdata = (struct help_command_data *) cd;
225
 
226
  hdata->filename = strdup (argv[2]);
227
  hdata->header_filename = strdup (argv[3]);
228
  return TCL_OK;
229
}
230
 
231
#define INIT_MINARGS (4)
232
#define INIT_MAXARGS (4)
233
 
234
/* Implement the ide_help topic command.  */
235
 
236
static int
237
help_topic_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
238
{
239
  struct help_command_data *hdata = (struct help_command_data *) cd;
240
  Tcl_HashEntry *he;
241
 
242
  if (help_initialize (interp, hdata) != TCL_OK)
243
    return TCL_ERROR;
244
 
245
  he = Tcl_FindHashEntry (&hdata->topic_hash, argv[2]);
246
  if (he == NULL)
247
    {
248
      Tcl_AppendResult (interp, "unknown help topic \"", argv[2], "\"",
249
                        (char *) NULL);
250
      return TCL_ERROR;
251
    }
252
 
253
  if (! WinHelp (hdata->window, hdata->filename, HELP_CONTEXT,
254
                 (DWORD) Tcl_GetHashValue (he)))
255
    {
256
      char buf[200];
257
 
258
      FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError (), 0,
259
                     buf, 200, NULL);
260
      Tcl_AppendResult (interp, "WinHelp failed: ", buf, (char *) NULL);
261
      return TCL_ERROR;
262
    }
263
 
264
  return TCL_OK;
265
}
266
 
267
/* Implement the ide_help toc command.  */
268
 
269
static int
270
help_toc_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
271
{
272
  struct help_command_data *hdata = (struct help_command_data *) cd;
273
 
274
  if (help_initialize (interp, hdata) != TCL_OK)
275
    return TCL_ERROR;
276
 
277
  if (! WinHelp (hdata->window, hdata->filename, HELP_FINDER, 0))
278
    {
279
      char buf[200];
280
 
281
      FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError (), 0,
282
                     buf, 200, NULL);
283
      Tcl_AppendResult (interp, "WinHelp failed: ", buf, (char *) NULL);
284
      return TCL_ERROR;
285
    }
286
 
287
  return TCL_OK;
288
}
289
 
290
/* Implement the ide_help display_file command.  */
291
/* This is a hack to display an external help file, */
292
/* by 'external' I mean not part of Foundry Help. */
293
/* This was added specifically to display the Foundry */
294
/* Tour help file and should be made less hacky in the future */
295
/* The "display_file" subcommand was added as a hack to get the Foundry Tour to */
296
/* launch.  The help system can't handle more than one help file and should */
297
/* be rewritten */
298
 
299
static int
300
help_display_file_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
301
{
302
  struct help_command_data *hdata = (struct help_command_data *) cd;
303
  FILE *e;
304
  DWORD   topic_id = 0; /* default topic id is 0 which brings up the find dialog */
305
 
306
  /* We call Help initialize just to make sure the window handle is setup */
307
  /* We don't care about the finding the main help file and checking the */
308
  /* hash table but we do it anyway because this is a hack. */
309
  if (help_initialize (interp, hdata) != TCL_OK)
310
    return TCL_ERROR;
311
 
312
  /* We should check to see if the help file we want exists since function */
313
  /* 'help_initialize' checked the wrong file (it checked the main help file) */
314
  e = fopen (argv[2], "r");
315
  if (e == NULL)
316
  {
317
          Tcl_AppendResult (interp, "can't open help file \"",
318
                argv[2], "\": ",
319
                            strerror (errno), (char *) NULL);
320
          return TCL_ERROR;
321
  }
322
  fclose (e);
323
  if (argc > 3)
324
  {
325
      if ( Tcl_GetInt (interp, argv[3], &topic_id) != TCL_OK )
326
        return TCL_ERROR;
327
  }
328
 
329
  if (! WinHelp (hdata->window, argv[2], HELP_CONTEXT, topic_id))
330
  {
331
      char buf[200];
332
 
333
      FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError (), 0,
334
                     buf, 200, NULL);
335
      Tcl_AppendResult (interp, "WinHelp failed: ", buf, (char *) NULL);
336
      return TCL_ERROR;
337
  }
338
 
339
  return TCL_OK;
340
}
341
 
342
/* Initialize the help command structure.  */
343
 
344
struct help_command_data *
345
hdata_initialize ()
346
{
347
  struct help_command_data *hdata;
348
 
349
  hdata = (struct help_command_data *) Tcl_Alloc (sizeof *hdata);
350
 
351
  hdata->filename = NULL;
352
  hdata->header_filename = NULL;
353
  hdata->hash_initialized = 0;
354
  hdata->window = NULL;
355
 
356
  return hdata;
357
}
358
 
359
#else /* ! _WIN32 */
360
 
361
/* The Unix help implementation. */
362
 
363
/* We use an instance of this structure as the client data for the
364
   ide_help command.  */
365
 
366
struct help_command_data
367
{
368
  /* path to webhelp.csh file */
369
  char *filename;
370
  /* path to foundry.hh file */
371
  char *header_filename;
372
  /* path to help directory */
373
  char *help_dir;
374
  /* A hash table mapping help topic strings to numbers. */
375
  Tcl_HashTable topic_hash;
376
  /* Nonzero if the hash table has been initialized. */
377
  int hash_initialized;
378
  /* pointer to large block of memory used for hashing */
379
  char *memory_block;
380
  };
381
 
382
/* This function is called if the ide_help command is deleted.  */
383
 
384
static void
385
help_command_deleted (ClientData cd)
386
{
387
  struct help_command_data *hdata = (struct help_command_data *) cd;
388
 
389
  if (hdata->filename != NULL)
390
    free (hdata->filename);
391
  if (hdata->header_filename != NULL)
392
    free (hdata->header_filename);
393
  if (hdata->hash_initialized)
394
    Tcl_DeleteHashTable (&hdata->topic_hash);
395
  if (hdata->memory_block != NULL)
396
    free (hdata->memory_block);
397
  Tcl_Free ((char *) hdata);
398
}
399
 
400
/* Implement the ide_help initialize command.  */
401
 
402
static int
403
help_initialize_command (ClientData cd, Tcl_Interp *interp, int argc,
404
             char **argv)
405
{
406
  struct help_command_data *hdata = (struct help_command_data *) cd;
407
 
408
  hdata->filename = strdup (argv[2]);
409
  hdata->header_filename = strdup (argv[3]);
410
  hdata->help_dir = strdup (argv[4]);
411
  return TCL_OK;
412
}
413
 
414
static int
415
help_initialize (Tcl_Interp *interp, struct help_command_data *hdata)
416
{
417
 
418
  if (hdata->filename == NULL || hdata->header_filename == NULL)
419
    {
420
      Tcl_SetResult (interp, "help system has not been initialized",
421
             TCL_STATIC);
422
      return TCL_ERROR;
423
    }
424
 
425
  if (! hdata->hash_initialized)
426
    {
427
      FILE *e;
428
      char buf[200], *block_start;
429
 
430
      block_start = hdata->memory_block = malloc(6000);
431
 
432
      e = fopen (hdata->header_filename, "r");
433
      if (e == NULL)
434
    {
435
      Tcl_AppendResult (interp, "can't open help file \"",
436
                hdata->header_filename, "\": ",
437
                strerror (errno), (char *) NULL);
438
      return TCL_ERROR;
439
    }
440
 
441
      Tcl_InitHashTable (&hdata->topic_hash, TCL_STRING_KEYS);
442
      hdata->hash_initialized = 1;
443
 
444
      /* We expect the format of the header file to be tightly
445
     constrained: the lines of interest will look like
446
         #define TOPIC_STRING TOPIC_FILENAME
447
     We ignore all other lines.  We assume that topic strings have
448
     a limited length, since they are created by humans, so for
449
     simplicity we use fgets with a fixed size buffer.  The error
450
     checking is minimal, but that's OK, because this file is part
451
     of the application; it is not created by the user.  */
452
 
453
      while (fgets (buf, sizeof buf, e) != NULL)
454
    {
455
      char *s, *topic, *strng;
456
      Tcl_HashEntry *he;
457
      int new;
458
 
459
      if (strncmp (buf, "#define", 7) != 0)
460
        continue;
461
 
462
      s = buf + 7;
463
      while (isspace ((unsigned char) *s))
464
        ++s;
465
      topic = s;
466
      while (! isspace ((unsigned char) *s))
467
        ++s;
468
      *s = '\0';
469
 
470
      ++s;
471
      while (isspace ((unsigned char) *s))
472
        ++s;
473
      strng = s;
474
      while (! isspace ((unsigned char) *s))
475
        ++s;
476
      *s = '\0';
477
      strcpy (block_start, strng);
478
 
479
      he = Tcl_CreateHashEntry (&hdata->topic_hash, topic, &new);
480
      Tcl_SetHashValue (he, (ClientData) block_start);
481
      block_start += strlen(strng) + 2;
482
 
483
    }
484
      fclose (e);
485
 
486
    }
487
 
488
  return TCL_OK;
489
 
490
}
491
 
492
#define INIT_MINARGS 2
493
#define INIT_MAXARGS 5
494
 
495
/* Implement the ide_help topic command.  */
496
 
497
static int
498
help_topic_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
499
{
500
  struct help_command_data *hdata = (struct help_command_data *) cd;
501
  Tcl_HashEntry *he;
502
  char htmlFile[250], htmlFile2[250];
503
 
504
  if (help_initialize (interp, hdata) != TCL_OK)
505
    return TCL_ERROR;
506
 
507
  he = Tcl_FindHashEntry (&hdata->topic_hash, argv[2]);
508
  if (he == NULL)
509
    {
510
      Tcl_AppendResult (interp, "unknown help topic \"", argv[2], "\"",
511
            (char *) NULL);
512
      return TCL_ERROR;
513
    }
514
  else
515
    {
516
 
517
     strcpy (htmlFile, hdata->help_dir);
518
     strcat (htmlFile, "/");
519
     strcat (htmlFile, Tcl_GetHashValue (he));
520
 
521
     ShowHelp (htmlFile, hdata->filename);
522
     return TCL_OK;
523
    }
524
}
525
 
526
/* Implement the ide_help toc command.  */
527
 
528
static int
529
help_toc_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
530
{
531
  struct help_command_data *hdata = (struct help_command_data *) cd;
532
  char htmlFile[250];
533
 
534
  strcpy (htmlFile, hdata->help_dir);
535
  strcat (htmlFile, "/start.htm");
536
 
537
  if (! ShowHelp (htmlFile, hdata->filename))
538
    { Tcl_SetResult (interp, "Help not available", TCL_STATIC);
539
      return TCL_ERROR;
540
    }
541
}
542
 
543
/* Implement the ide_help display command.  */
544
 
545
static int
546
help_display_file_command (ClientData cd, Tcl_Interp *interp, int argc, char **argv)
547
{
548
  struct help_command_data *hdata = (struct help_command_data *) cd;
549
 
550
  if (! ShowHelp (argv[2], hdata->filename))
551
    { Tcl_SetResult (interp, "Help not available", TCL_STATIC);
552
      return TCL_ERROR;
553
    }
554
}
555
 
556
/* Initialize the help command structure.  */
557
 
558
struct help_command_data *
559
hdata_initialize ()
560
{
561
  struct help_command_data *hdata;
562
 
563
  hdata = (struct help_command_data *) Tcl_Alloc (sizeof *hdata);
564
 
565
  hdata->filename = NULL;
566
  hdata->help_dir = NULL;
567
  hdata->header_filename = NULL;
568
  hdata->hash_initialized = 0;
569
  hdata->memory_block = NULL;
570
 
571
  return hdata;
572
}
573
 
574
int
575
ShowHelp(const char* html_filename, const char* shellFile)
576
{
577
  int pidProcess = fork();
578
  if (pidProcess == 0)
579
    {
580
    /* new child process */
581
    execl("/bin/csh", "/bin/csh", shellFile, html_filename, 0);
582
    /* execl only returns if error occurred */
583
     _exit(-1);
584
    }
585
  /* fork failed, error number is why */
586
  else if (pidProcess == (-1))
587
    { return 0; }
588
}
589
 
590
#endif /* ! _WIN32 */
591
 
592
/* The subcommand table.  */
593
/* The "display_file" subcommand was added as a hack to get the Foundry Tour to */
594
/* launch.  The help system can't handle more than one help file and should */
595
/* be rewritten */
596
static const struct ide_subcommand_table help_commands[] =
597
{
598
  { "initialize",       help_initialize_command, INIT_MINARGS, INIT_MAXARGS },
599
  { "topic",            help_topic_command,      3, 3 },
600
  { "toc",              help_toc_command,        2, 2 },
601
  { "display_file",      help_display_file_command,    3, 4 },
602
  { NULL, NULL, 0, 0 }
603
};
604
 
605
/* This function creates the ide_help TCL command.  */
606
 
607
int
608
ide_create_help_command (Tcl_Interp *interp)
609
{
610
  struct help_command_data *hdata;
611
 
612
  hdata = hdata_initialize ();
613
 
614
  return ide_create_command_with_subcommands (interp, "ide_help",
615
                                              help_commands,
616
                                              (ClientData) hdata,
617
                                              help_command_deleted);
618
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.