~ubuntu-branches/debian/sid/menu/sid

« back to all changes in this revision

Viewing changes to menu-method/menu-method.cc

  • Committer: Bazaar Package Importer
  • Author(s): Bill Allombert
  • Date: 2005-05-24 10:34:47 UTC
  • mfrom: (1.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050524103447-9zu50so5d0nte3o9
Tags: 2.1.24
* The "head or tail" release 
* Fix .menus typo in menufile.5. Closes: #306564. Thanks Sean Finney.
* Add Vietnamese menu messages and menu sections translations.
  Thanks Clytie Siddall. Closes: #307450, #308953.
* Update Esperanto menu sections translation. Thanks MJ Ray.
* Add Esperanto menu messages translation. Thanks MJ Ray.
* Unfuzzy Norwegian Bokmål menu messages translation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include <strstream.h>
2
 
#include <iostream.h>
3
 
#include <fstream.h>
4
 
#include <set.h>
5
 
#include <list.h>
6
 
#include <getopt.h>
7
 
#include <ctype.h>
8
 
#include <unistd.h>
9
 
#include <stdlib.h>
10
 
#include <values.h>
11
 
#include <sys/types.h>
12
 
#include <dirent.h>
13
 
#include <fcntl.h>
14
 
#include <unistd.h>
15
 
#include <sys/stat.h>
16
 
 
17
 
#include "menu-method.h"
18
 
#include "menu-tree.h"
19
 
 
20
 
int show_time=0, verbose=0, dodebug=0;
21
 
 
22
 
map <String, func *, less<String> > func_data;
23
 
 
24
 
menuentry menu;
25
 
configinfo *config;
26
 
supportedinfo *supported;
27
 
int linenumber=-123456;
28
 
 
29
 
ofstream *genoutputfile=NULL;
30
 
set<String> outputnames; //all names of files ever written to
31
 
 
32
 
 
33
 
struct option long_options[] = { 
34
 
  { "showtime", no_argument, &show_time, 1 }, 
35
 
  { "verbose", no_argument, &verbose, 1 }, 
36
 
  { "debug", no_argument, &dodebug, 1 }, 
37
 
  { "help", no_argument, NULL, 'h' }, 
38
 
  { "stdin", no_argument, NULL, 'f' }, 
39
 
  { NULL, 0, NULL, 0 } };
40
 
 
41
 
void usage(){
42
 
  cerr<<"menu-method: generate window-manager 'rc' files (or html docs)"<<endl
43
 
      <<"  menu-method gets the menuentries from standard in."<<endl
44
 
      <<"  Options to menu-method: "<<endl
45
 
      <<"     -h --help : this message"<<endl
46
 
      <<"     -d --debug: show debug info"<<endl
47
 
      <<"     -showtime : show timeing information"<<endl;
48
 
  exit(1);
49
 
}
50
 
 
51
 
func_def::~func_def(){
52
 
}
53
 
 
54
 
void store_func(func *f){
55
 
  func_data[f->name()]=f;
56
 
}
57
 
void add_functions(){
58
 
  store_func(new prefix_func);
59
 
  store_func(new ifroot_func);
60
 
 
61
 
  store_func(new print_func);
62
 
  store_func(new add_func);
63
 
  store_func(new sub_func);
64
 
  store_func(new mult_func);
65
 
  store_func(new div_func);
66
 
  store_func(new ifempty_func);
67
 
  store_func(new ifnempty_func);
68
 
  store_func(new iffile_func);
69
 
  store_func(new ifelsefile_func);
70
 
  store_func(new ifelse_func);
71
 
  store_func(new catfile_func);
72
 
 
73
 
  store_func(new ifeq_func);
74
 
  store_func(new ifneq_func);
75
 
  store_func(new ifeqelse_func);
76
 
 
77
 
  store_func(new cond_surr_func);
78
 
  store_func(new esc_func);
79
 
  store_func(new escwith_func);
80
 
  store_func(new escfirst_func);
81
 
  store_func(new tolower_func);  
82
 
  store_func(new toupper_func);
83
 
  store_func(new replacewith_func);
84
 
  store_func(new nstring_func);  
85
 
  store_func(new cppesc_func);
86
 
  store_func(new parent_func);
87
 
  store_func(new basename_func);
88
 
  store_func(new entrycount_func);
89
 
  store_func(new entryindex_func);
90
 
  store_func(new firstentry_func);
91
 
  store_func(new lastentry_func);
92
 
  store_func(new level_func);
93
 
 
94
 
  store_func(new rcfile_func);
95
 
  store_func(new examplercfile_func);
96
 
  store_func(new mainmenutitle_func);
97
 
  store_func(new rootsection_func);
98
 
  store_func(new rootprefix_func);
99
 
  store_func(new userprefix_func);
100
 
  store_func(new treewalk_func);
101
 
  store_func(new postoutput_func);
102
 
  store_func(new preoutput_func);
103
 
}
104
 
 
105
 
 
106
 
bool empty_String(const String &s){
107
 
  if(s.length()&&(s!=String("none")))
108
 
    return false;
109
 
  else
110
 
    return true;
111
 
}
112
 
 
113
 
 
114
 
cat_str *get_eq_cat_str(parsestream &i){
115
 
  i.skip_space();
116
 
  i.skip_char('=');
117
 
  return new cat_str(i);
118
 
}
119
 
 
120
 
int check_dir(String s){
121
 
  String t;
122
 
  unsigned int i;
123
 
  if(dodebug)
124
 
    cerr<<"CHECK_DIR: "<<s<<endl;
125
 
  while(s.length()){
126
 
    i=s.find('/',1);
127
 
    if(i<s.length()){
128
 
      t=s.substr(0,i+1);
129
 
      for(; ((unsigned int)i<s.length()) && (s[i]=='/'); i++);
130
 
      s=s.substr(s.begin()+i,s.end());
131
 
    } else {
132
 
      t=s;
133
 
      s="";
134
 
    }
135
 
    if(chdir(t.c_str())<0){
136
 
      if(dodebug)
137
 
        cerr<<"MKDIR "<<t<<endl;
138
 
      if(mkdir(t.c_str(),0755))
139
 
        throw dir_createerror(t);
140
 
      if(chdir(t.c_str()))
141
 
        throw dir_createerror(t);
142
 
    } else {
143
 
      if(dodebug)
144
 
        cerr<<" dir "<<t<<" already exists "<<endl;
145
 
    }
146
 
  }
147
 
  return !s.length();
148
 
}
149
 
 
150
 
void closegenoutput(){
151
 
  set<String>::iterator i;
152
 
 
153
 
  // OK, this will look clumsy in strace output, especially if there's
154
 
  // only output file: first we close, and immediately afterwards we
155
 
  // open and write again. But I don't see an easy and general way
156
 
  // to get round that.
157
 
  if(genoutputfile){
158
 
    delete genoutputfile;
159
 
    genoutputfile=NULL;
160
 
  }
161
 
  for(i=outputnames.begin(); i!=outputnames.end(); i++){
162
 
    ofstream f((*i).c_str(), ios::app);
163
 
    f<<(config->postoutput());
164
 
  }
165
 
}
166
 
void genoutput(const String &s,
167
 
               map<String, String, less<String> > &v){
168
 
  
169
 
  static String lastname="////";
170
 
  String name;
171
 
  String dir;
172
 
 
173
 
  name=config->prefix()+"/"+config->genmenu->soutput(v);
174
 
  //if(dodebug)
175
 
  //  cerr<<"GENOUTPUT: name="<<name<<endl;
176
 
  if(name!=lastname){
177
 
    if(genoutputfile)
178
 
      delete genoutputfile;
179
 
    if(outputnames.find(name)==outputnames.end()){
180
 
      outputnames.insert(name);
181
 
      check_dir(String_parent(name));
182
 
      // after opening a file with ios::trunc, all writes seem to fail!
183
 
      //genoutputfile=new ofstream(name.c_str(), ios::trunc);
184
 
      // So, I do it this way instead:
185
 
      unlink(name.c_str());
186
 
      genoutputfile=new ofstream(name.c_str());
187
 
      (*genoutputfile)<<config->preoutput();    
188
 
    } else
189
 
      genoutputfile=new ofstream(name.c_str(),ios::app);      
190
 
    lastname=name;
191
 
  }
192
 
  (*genoutputfile)<<s;
193
 
}
194
 
 
195
 
/////////////////////////////////////////////////////
196
 
//  Construction:
197
 
//
198
 
 
199
 
str::~str(){
200
 
}
201
 
cat_str::cat_str(parsestream &i){
202
 
  char c;
203
 
  c=i.get_char();
204
 
  i.put_back(c);
205
 
  try{
206
 
    while(1){
207
 
      i.skip_space();
208
 
      c=i.get_char();
209
 
      i.put_back(c);
210
 
      if(isalpha(c))
211
 
        v.push_back(new func_str(i));
212
 
      else if(c=='\"') 
213
 
        v.push_back(new const_str(i));
214
 
      else if(c=='$') 
215
 
        v.push_back(new var_str(i));
216
 
      else if(c==',')
217
 
        break;
218
 
      else if(c==')')
219
 
        break;
220
 
      else if(c=='\0')
221
 
        break;
222
 
      else
223
 
        throw char_unexpected(&i, c);
224
 
    }
225
 
  }catch(endofline p){};
226
 
}
227
 
 
228
 
const_str::const_str(parsestream &i){
229
 
  data=i.get_Stringconst();
230
 
}
231
 
 
232
 
var_str::var_str(parsestream &i){
233
 
  i.skip_char('$');
234
 
  var_name=i.get_name();
235
 
}
236
 
 
237
 
func_str::func_str(parsestream &i){
238
 
  char c;
239
 
  String name;
240
 
  map <String, func *, less<String> >::iterator j;
241
 
 
242
 
  name=i.get_name();
243
 
  j=func_data.find(name);
244
 
  if(j==func_data.end()){
245
 
    throw unknown_function(&i);
246
 
  } else
247
 
    f=(*j).second;
248
 
 
249
 
  i.skip_space();
250
 
  i.skip_char('(');
251
 
  do{
252
 
    i.skip_space();
253
 
    c=i.get_char();
254
 
    if(c==')')
255
 
      break;
256
 
    i.put_back(c);
257
 
    args.push_back(new cat_str(i));
258
 
    i.skip_space();
259
 
  } while((c=i.get_char())&&(c==','));
260
 
  i.put_back(c);
261
 
  i.skip_char(')');
262
 
  if(args.size()!=(unsigned int)f->nargs())
263
 
    throw narg_mismatch(&i, name);
264
 
}
265
 
 
266
 
 
267
 
/////////////////////////////////////////////////////
268
 
//  Output routines
269
 
//
270
 
 
271
 
ostream &const_str::output(ostream &o, 
272
 
                           map<String, String, less<String> > &/*menuentry*/){
273
 
  //  cout<<"IN CONST_STR: data="<<data<<endl;
274
 
  return o<<data;
275
 
}
276
 
 
277
 
String cat_str::soutput(map<String, String, less<String> > &menuentry){
278
 
  char buf[MAX_BUF];
279
 
  vector <str * >::iterator i;
280
 
  ostrstream s(buf,sizeof(buf));
281
 
  
282
 
  //cout<<"CONFIG->rfc="<<config->rcff()<<endl;
283
 
  
284
 
  for(i=v.begin();i!=v.end();i++){
285
 
    //char Duf[MAX_BUF];
286
 
    //ostrstream D(Duf,sizeof(buf));
287
 
    (*i)->output(s,menuentry);
288
 
    //(*i)->output(D,menuentry);
289
 
    //D<<ends;
290
 
    //cout<<"DDD "<<Duf<<endl;
291
 
  }
292
 
  s<<ends;
293
 
  
294
 
  return String(buf);
295
 
}
296
 
ostream &cat_str::output(ostream &o, 
297
 
                         map<String, String, less<String> > &menuentry){
298
 
  o<<soutput(menuentry);
299
 
  return o;
300
 
}
301
 
void cat_str::output(map<String, String, less<String> > &menuentry){
302
 
  genoutput(soutput(menuentry),menuentry);
303
 
}
304
 
 
305
 
ostream &var_str::output(ostream &o,
306
 
                         map<String, String, less<String> > &menuentry){
307
 
  return o<<menuentry[var_name];
308
 
}
309
 
ostream &func_str::output(ostream &o,
310
 
                         map<String, String, less<String> > &menuentry){
311
 
  return f->output(o,args,menuentry);
312
 
}
313
 
 
314
 
/////////////////////////////////////////////////////
315
 
//  Debug routines
316
 
//
317
 
ostream &const_str::debuginfo(ostream &o){
318
 
  return o<<"CONST_STR: "<<data<<endl;
319
 
}
320
 
ostream &cat_str::debuginfo(ostream &o){
321
 
  vector<str *>::iterator i;
322
 
  o<<"CAT_STR: "<<endl;
323
 
  for(i=v.begin();i!=v.end();i++){
324
 
    (*i)->debuginfo(o);
325
 
  }
326
 
  return o;
327
 
}
328
 
ostream &var_str::debuginfo(ostream &o){
329
 
  return o<<"VAR_STR: "<<var_name<<endl;
330
 
}
331
 
ostream &func_str::debuginfo(ostream &o){
332
 
  o<<"FUNC_STR: "<<f->name()<<" ("<<endl;
333
 
  vector<cat_str *>::iterator i;  
334
 
  for(i=args.begin();i!=args.end();i++){
335
 
    o<<", ";
336
 
    (*i)->debuginfo(o);
337
 
  }
338
 
  return o<<")"<<endl;
339
 
}
340
 
 
341
 
 
342
 
/////////////////////////////////////////////////////
343
 
//  Function definitions:
344
 
//
345
 
 
346
 
ostream &prefix_func::output(ostream &o, vector<cat_str *> &,
347
 
                             map<String, String, less<String> > &){
348
 
 
349
 
  return o<<config->prefix();
350
 
}
351
 
ostream &ifroot_func::output(ostream &o, vector<cat_str *> & args,
352
 
                             map<String, String, less<String> > &menuentry){
353
 
  if(getuid())
354
 
    args[1]->output(o,menuentry);
355
 
  else
356
 
    args[0]->output(o,menuentry);
357
 
 
358
 
  return o;
359
 
}
360
 
 
361
 
ostream &print_func::output(ostream &o, vector<cat_str *> &args,
362
 
                            map<String, String, less<String> > &menuentry){
363
 
 
364
 
  String s=args[0]->soutput(menuentry);
365
 
 
366
 
  if(empty_String(s)){
367
 
    cerr<<"Zero-size argument to print function";
368
 
    throw informed_fatal();
369
 
  }
370
 
  return o<<s;
371
 
}
372
 
ostream &ifempty_func::output(ostream &o, vector<cat_str *> &args,
373
 
                              map<String, String, less<String> > &menuentry){
374
 
 
375
 
  String s=args[0]->soutput(menuentry);
376
 
 
377
 
  if(empty_String(s))
378
 
    args[1]->output(o,menuentry);
379
 
  return o;
380
 
}
381
 
ostream &ifnempty_func::output(ostream &o, vector<cat_str *> &args,
382
 
                               map<String, String, less<String> > &menuentry){
383
 
 
384
 
  String s=args[0]->soutput(menuentry);
385
 
  if(!empty_String(s))
386
 
    args[1]->output(o,menuentry);
387
 
  return o;
388
 
}
389
 
ostream &iffile_func::output(ostream &o, vector<cat_str *> &args,
390
 
                             map<String, String, less<String> > &menuentry){
391
 
 
392
 
  String s=args[0]->soutput(menuentry);
393
 
  ifstream f(s.c_str());
394
 
  if(f)
395
 
    args[1]->output(o,menuentry);
396
 
  return o;
397
 
}
398
 
ostream &ifelsefile_func::output(ostream &o, vector<cat_str *> &args,
399
 
                             map<String, String, less<String> > &menuentry){
400
 
 
401
 
  String s=args[0]->soutput(menuentry);
402
 
  ifstream f(s.c_str());
403
 
  if(f)
404
 
    args[1]->output(o,menuentry);
405
 
  else
406
 
    args[2]->output(o,menuentry);
407
 
  return o;
408
 
}
409
 
ostream &catfile_func::output(ostream &o, vector<cat_str *> &args,
410
 
                             map<String, String, less<String> > &menuentry){
411
 
 
412
 
  String s=args[0]->soutput(menuentry);
413
 
  ifstream f(s.c_str());
414
 
  char c;
415
 
 
416
 
  while(f && f.get(c))
417
 
    o<<c;
418
 
  return o;
419
 
}
420
 
 
421
 
ostream &esc_func::output(ostream &o, vector<cat_str *> &args,
422
 
                          map<String, String, less<String> > &menuentry){
423
 
 
424
 
  return o<<escape_String(args[0]->soutput(menuentry),
425
 
                          args[1]->soutput(menuentry));
426
 
}
427
 
ostream &escwith_func::output(ostream &o, vector<cat_str *> &args,
428
 
                              map<String, String, less<String> > &menuentry){
429
 
 
430
 
  return o<<escapewith_String(args[0]->soutput(menuentry),
431
 
                              args[1]->soutput(menuentry),
432
 
                              args[2]->soutput(menuentry));
433
 
}
434
 
ostream &escfirst_func::output(ostream &o, vector<cat_str *> &args,
435
 
                              map<String, String, less<String> > &menuentry){
436
 
 
437
 
  String s=args[0]->soutput(menuentry);
438
 
  String esc=args[1]->soutput(menuentry);
439
 
  String t;
440
 
  int  i;
441
 
 
442
 
  for(i=0;(unsigned int)i!=s.length();i++){
443
 
    if(esc.length() && esc.contains(s[i])){
444
 
      t=s.substr(0,i);
445
 
      t+=args[2]->soutput(menuentry);
446
 
      t+=s.substr(s.begin()+i,s.end());
447
 
      break;
448
 
    }
449
 
    t+=s[i];
450
 
  }
451
 
  return o<<t;
452
 
}
453
 
ostream &tolower_func::output(ostream &o, vector<cat_str *> &args,
454
 
                              map<String, String, less<String> > &menuentry){
455
 
 
456
 
  return o<<tolower_String(args[0]->soutput(menuentry));
457
 
}
458
 
ostream &toupper_func::output(ostream &o, vector<cat_str *> &args,
459
 
                                  map<String, String, less<String> > &menuentry){
460
 
 
461
 
  return o<<toupper_String(args[0]->soutput(menuentry));
462
 
}
463
 
ostream &replacewith_func::output(ostream &o, vector<cat_str *> &args,
464
 
                                  map<String, String, less<String> > &menuentry){
465
 
 
466
 
  return o<<replacewith_String(args[0]->soutput(menuentry),
467
 
                               args[1]->soutput(menuentry),
468
 
                               args[2]->soutput(menuentry));
469
 
}
470
 
ostream &nstring_func::output(ostream &o, vector<cat_str *> &args,
471
 
                            map<String, String, less<String> > &menuentry){
472
 
  int count= Stringtoi(args[0]->soutput(menuentry));
473
 
  int i;
474
 
 
475
 
  for(i=0; i<count; i++)
476
 
    o<<args[1]->soutput(menuentry);
477
 
 
478
 
  return o;
479
 
}
480
 
ostream &cppesc_func::output(ostream &o, vector<cat_str *> &args,
481
 
                              map<String, String, less<String> > &menuentry){
482
 
 
483
 
  return o<<cppesc_String(args[0]->soutput(menuentry));
484
 
}
485
 
 
486
 
ostream &add_func::output(ostream &o, vector<cat_str *> &args,
487
 
                          map<String, String, less<String> > &menuentry){
488
 
 
489
 
  int x=Stringtoi(args[0]->soutput(menuentry));
490
 
  int y=Stringtoi(args[1]->soutput(menuentry));
491
 
 
492
 
  return o<<itoString(x+y);
493
 
}
494
 
ostream &sub_func::output(ostream &o, vector<cat_str *> &args,
495
 
                          map<String, String, less<String> > &menuentry){
496
 
 
497
 
  int x=Stringtoi(args[0]->soutput(menuentry));
498
 
  int y=Stringtoi(args[1]->soutput(menuentry));
499
 
 
500
 
  return o<<itoString(x-y);
501
 
}
502
 
ostream &mult_func::output(ostream &o, vector<cat_str *> &args,
503
 
                          map<String, String, less<String> > &menuentry){
504
 
 
505
 
  int x=Stringtoi(args[0]->soutput(menuentry));
506
 
  int y=Stringtoi(args[1]->soutput(menuentry));
507
 
 
508
 
  return o<<itoString(x*y);
509
 
}
510
 
ostream &div_func::output(ostream &o, vector<cat_str *> &args,
511
 
                          map<String, String, less<String> > &menuentry){
512
 
 
513
 
  int x=Stringtoi(args[0]->soutput(menuentry));
514
 
  int y=Stringtoi(args[1]->soutput(menuentry));
515
 
  
516
 
  if(y)
517
 
    return o<<itoString(x/y);
518
 
  else
519
 
    return o<<"0";
520
 
}
521
 
 
522
 
ostream &ifelse_func::output(ostream &o, vector<cat_str *> &args,
523
 
                             map<String, String, less<String> > &menuentry){
524
 
 
525
 
  String s=args[0]->soutput(menuentry);
526
 
 
527
 
  (!empty_String(s)) ?
528
 
    args[1]->output(o,menuentry)
529
 
    :
530
 
    args[2]->output(o,menuentry);
531
 
  return o;
532
 
}
533
 
ostream &ifeq_func::output(ostream &o, vector<cat_str *> &args,
534
 
                           map<String, String, less<String> > &menuentry){
535
 
 
536
 
  String s=args[0]->soutput(menuentry);
537
 
  String t=args[1]->soutput(menuentry);
538
 
  if(s==t)
539
 
    args[2]->output(o,menuentry);
540
 
  
541
 
  return o;
542
 
}
543
 
ostream &ifneq_func::output(ostream &o, vector<cat_str *> &args,
544
 
                           map<String, String, less<String> > &menuentry){
545
 
 
546
 
  String s=args[0]->soutput(menuentry);
547
 
  String t=args[1]->soutput(menuentry);
548
 
  if(!(s==t))
549
 
    args[2]->output(o,menuentry);
550
 
  
551
 
  return o;
552
 
}
553
 
ostream &ifeqelse_func::output(ostream &o, vector<cat_str *> &args,
554
 
                           map<String, String, less<String> > &menuentry){
555
 
 
556
 
  String s=args[0]->soutput(menuentry);
557
 
  String t=args[1]->soutput(menuentry);
558
 
  if(s==t)
559
 
    args[2]->output(o,menuentry);
560
 
  else
561
 
    args[3]->output(o,menuentry);
562
 
 
563
 
  return o;
564
 
}
565
 
 
566
 
ostream &cond_surr_func::output(ostream &o, vector<cat_str *> &args,
567
 
                                map<String, String, less<String> > &menuentry){
568
 
 
569
 
  String s=args[0]->soutput(menuentry);
570
 
 
571
 
  if(!empty_String(s)){
572
 
    args[1]->output(o,menuentry);
573
 
    args[0]->output(o,menuentry);
574
 
    args[2]->output(o,menuentry);
575
 
  }
576
 
  return o;
577
 
}
578
 
 
579
 
ostream &parent_func::output(ostream &o, vector<cat_str *> &args,
580
 
                             map<String, String, less<String> > &menuentry){
581
 
 
582
 
  String s=args[0]->soutput(menuentry);
583
 
 
584
 
  return o<<String_parent(s);
585
 
}
586
 
 
587
 
ostream &basename_func::output(ostream &o, vector<cat_str *> &args,
588
 
                               map<String, String, less<String> > &menuentry){
589
 
 
590
 
  String s=args[0]->soutput(menuentry);
591
 
  
592
 
  return o<<String_basename(s);
593
 
}
594
 
ostream &entrycount_func::output(ostream &o, vector<cat_str *> &/*args*/,
595
 
                                 map<String, String, less<String> > &menuentry){
596
 
  return o<<menuentry[PRIVATE_ENTRYCOUNT_VAR];
597
 
}
598
 
ostream &entryindex_func::output(ostream &o, vector<cat_str *> &/*args*/,
599
 
                                 map<String, String, less<String> > &menuentry){
600
 
  return o<<menuentry[PRIVATE_ENTRYINDEX_VAR];
601
 
}
602
 
ostream &firstentry_func::output(ostream &o, vector<cat_str *> &args,
603
 
                                 map<String, String, less<String> > &menuentry){
604
 
  int index=Stringtoi(menuentry[PRIVATE_ENTRYINDEX_VAR]);
605
 
 
606
 
  if(index == 0)
607
 
    args[0]->output(o,menuentry);
608
 
  return o;
609
 
}
610
 
 
611
 
ostream &lastentry_func::output(ostream &o, vector<cat_str *> &args,
612
 
                                 map<String, String, less<String> > &menuentry){
613
 
 
614
 
  int index=Stringtoi(menuentry[PRIVATE_ENTRYINDEX_VAR]);
615
 
  int count=Stringtoi(menuentry[PRIVATE_ENTRYCOUNT_VAR]);
616
 
 
617
 
  if(index+1 == count)
618
 
    args[0]->output(o,menuentry);
619
 
  return o;
620
 
}
621
 
 
622
 
 
623
 
ostream &level_func::output(ostream &o, vector<cat_str *> &/*args*/,
624
 
                                 map<String, String, less<String> > &menuentry){
625
 
  return o<<menuentry[PRIVATE_LEVEL_VAR];
626
 
}
627
 
 
628
 
 
629
 
ostream &rcfile_func::output(ostream &o, vector<cat_str *> &/*args*/,
630
 
                                 map<String, String, less<String> > &menuentry){
631
 
  return o<<config->rcfile();
632
 
}
633
 
ostream &examplercfile_func::output(ostream &o, vector<cat_str *> &/*args*/,
634
 
                                 map<String, String, less<String> > &menuentry){
635
 
  return o<<config->examplercfile();
636
 
}
637
 
ostream &mainmenutitle_func::output(ostream &o, vector<cat_str *> &/*args*/,
638
 
                                 map<String, String, less<String> > &menuentry){
639
 
  return o<<config->mainmenutitle();
640
 
}
641
 
ostream &rootsection_func::output(ostream &o, vector<cat_str *> &/*args*/,
642
 
                                 map<String, String, less<String> > &menuentry){
643
 
  return o<<config->rootsection();
644
 
}
645
 
ostream &rootprefix_func::output(ostream &o, vector<cat_str *> &/*args*/,
646
 
                                 map<String, String, less<String> > &menuentry){
647
 
  return o<<config->rootprefix();
648
 
}
649
 
ostream &userprefix_func::output(ostream &o, vector<cat_str *> &/*args*/,
650
 
                                 map<String, String, less<String> > &menuentry){
651
 
  return o<<config->userprefix();
652
 
}
653
 
ostream &treewalk_func::output(ostream &o, vector<cat_str *> &/*args*/,
654
 
                                 map<String, String, less<String> > &menuentry){
655
 
  return o<<config->treewalk();
656
 
}
657
 
ostream &postoutput_func::output(ostream &o, vector<cat_str *> &/*args*/,
658
 
                                 map<String, String, less<String> > &menuentry){
659
 
  return o<<config->postoutput();
660
 
}
661
 
ostream &preoutput_func::output(ostream &o, vector<cat_str *> &/*args*/,
662
 
                                map<String, String, less<String> > &menuentry){
663
 
  return o<<config->preoutput();
664
 
}
665
 
 
666
 
 
667
 
/////////////////////////////////////////////////////
668
 
//  "defined" function (macro).
669
 
//
670
 
 
671
 
ostream &func_def::output(ostream &o, vector<cat_str *> &args,
672
 
                          map<String, String, less<String> > &menuentry){
673
 
 
674
 
  String t;
675
 
  unsigned int i;
676
 
  map<String, String, less<String> > local_menuentry=menuentry;
677
 
 
678
 
  for(i=0; i<args_name.size(); i++)
679
 
    local_menuentry[args_name[i]]=args[i]->soutput(menuentry);
680
 
 
681
 
  f->output(o,local_menuentry);
682
 
  return o;
683
 
}
684
 
func_def::func_def(parsestream &i){
685
 
  char c;
686
 
 
687
 
  n=i.get_name();
688
 
  i.skip_space();
689
 
  i.skip_char('(');
690
 
  do{
691
 
    i.skip_space();
692
 
    c=i.get_char();
693
 
    if(c==')')
694
 
      break;
695
 
    i.put_back(c);
696
 
    i.skip_char('$');
697
 
    args_name.push_back(i.get_name());
698
 
    i.skip_space();
699
 
  } while((c=i.get_char())&&(c==','));
700
 
  i.put_back(c);
701
 
  i.skip_char(')');
702
 
  i.skip_space();
703
 
  i.skip_char('=');
704
 
  f=new cat_str(i);
705
 
}
706
 
 
707
 
/////////////////////////////////////////////////////
708
 
//  Supported stuff
709
 
//
710
 
 
711
 
supportedinfo::supportedinfo(parsestream &i){
712
 
  linenumber=1;
713
 
  int prec=0;
714
 
  while(1){
715
 
    try{
716
 
      String name;
717
 
      i.skip_space();
718
 
      name=i.get_name();
719
 
      if(name==String("endsupported"))
720
 
        return;
721
 
      name=upcase(name);
722
 
      if(dodebug)
723
 
        cerr<<"SUPPORTED_CONSTRUCT: name="<<name<<endl;
724
 
      
725
 
      supinf inf;
726
 
      inf.c=get_eq_cat_str(i);
727
 
      inf.prec=prec++;
728
 
      sup[name]=inf;
729
 
      if(dodebug)
730
 
        sup[name].c->debuginfo(cerr);
731
 
      i.skip_line();   //read away the final newline
732
 
    }
733
 
    catch(endofline d){}
734
 
  }
735
 
}
736
 
 
737
 
void supportedinfo::subst(map<String, String, less<String> > vars){
738
 
 
739
 
  map<String, String, less<String> >::iterator i;
740
 
  map<String, supinf, less<String> >::iterator j;
741
 
 
742
 
  if((i=vars.find(NEEDS_VAR))==vars.end()){
743
 
    cerr<<"Undefined "NEEDS_VAR" variable in menuentries"<<endl;
744
 
    throw informed_fatal();
745
 
  }
746
 
  if((j=sup.find(upcase((*i).second)))==sup.end()){
747
 
    cerr<<"Unknown "NEEDS_VAR"=\""<<(*i).second<<"\""<<endl;
748
 
    throw informed_fatal();
749
 
  }
750
 
  genoutput((*j).second.c->soutput(vars), vars);
751
 
}
752
 
int supportedinfo::prec(String &name){
753
 
  map<String, supinf, less<String> >::iterator i;
754
 
  int p;
755
 
  if((i=sup.find(upcase(name)))==sup.end())
756
 
    p=MAXINT;
757
 
  else
758
 
    p=(*i).second.prec;
759
 
  //if(dodebug)
760
 
  //  cerr<<"PREC: name="<<upcase(name)<<"="<<p<<endl;
761
 
  return p;
762
 
}
763
 
 
764
 
ostream &supportedinfo::debuginfo(ostream &o){
765
 
  map<String, supinf, less<String> >::iterator i;
766
 
  for(i=sup.begin();i!=sup.end();i++){
767
 
    o<<"SUPPORTED:** name="<<(*i).first<<", prec="
768
 
        <<(*i).second.prec<<" Def="<<endl;
769
 
    (*i).second.c->debuginfo(o);
770
 
  }
771
 
  return o;
772
 
}
773
 
/////////////////////////////////////////////////////
774
 
//  forcetree stuff
775
 
//
776
 
 
777
 
void read_forcetree(parsestream &i){
778
 
  Regex r("[a-zA-Z/-_ ]");
779
 
 
780
 
  while(1){
781
 
    try{
782
 
      String name;
783
 
      StrVec v;
784
 
      menuentry *m;
785
 
 
786
 
      i.skip_space();
787
 
      name=i.get_name(r);
788
 
      if(!name.size())
789
 
        throw ident_expected(&i);
790
 
      if(name==String("endforcetree"))
791
 
        return;
792
 
      
793
 
      break_slashes(name,v);
794
 
      m=new menuentry;
795
 
      m->forced=true;
796
 
      m->vars[TITLE_VAR]=v[v.size()-1];
797
 
      menu.add_menuentry_ptr(v,m);  
798
 
      i.skip_line();
799
 
    }
800
 
    catch(endofline d){}
801
 
  }
802
 
  
803
 
}
804
 
/////////////////////////////////////////////////////
805
 
//  configinfo
806
 
//
807
 
configinfo::configinfo(parsestream &i){
808
 
  String errmsg("Parse error: String constant expected");
809
 
  linenumber=1;
810
 
  treew="c(m)";
811
 
  sort=prerun=preruntest=postrun=genmenu=
812
 
    hkexclude=startmenu=endmenu=submenutitle=NULL;
813
 
  mainmt="Debian";
814
 
  onlyrunasroot=onlyrunasuser=false;
815
 
 
816
 
  hint_optimize=false;
817
 
  hint_nentry=6;
818
 
  hint_topnentry=5;
819
 
  hint_mixedpenalty=15;
820
 
  hint_minhintfreq=0.1;
821
 
  hint_mlpenalty=2000;
822
 
  hint_max_ntry=4;
823
 
  hint_max_iter_hint=5;
824
 
  hint_debug=false;
825
 
 
826
 
  //minhintfreq=0.1;
827
 
  //hintdebug=false;
828
 
  //n_entry_opt=6;
829
 
  //hint_toplevel_nopt=5;
830
 
  //hint_mlpenalty=20;
831
 
  //keep_sections=true;
832
 
 
833
 
  preout="#Automatically generated file. Do not edit (see /usr/doc/menu/html/index.html)\n\n";
834
 
  postout="";
835
 
  roots="/Debian";
836
 
  try{
837
 
    while(1){
838
 
        String name;
839
 
        name=i.get_name();
840
 
        if(name==String("supported")){
841
 
          i.skip_line();
842
 
          supported=new supportedinfo(i);
843
 
        } else if(name==String("forcetree")){
844
 
          i.skip_line();
845
 
          read_forcetree(i);
846
 
        } 
847
 
        else if(name==String("function"))
848
 
          store_func(new func_def(i));
849
 
        else if(name==String("startmenu"))
850
 
          startmenu=get_eq_cat_str(i);
851
 
        else if(name==String("endmenu"))
852
 
          endmenu=get_eq_cat_str(i);
853
 
        else if(name==String("submenutitle"))
854
 
          submenutitle=get_eq_cat_str(i);
855
 
        else if(name==String("hotkeyexclude"))
856
 
          hkexclude=get_eq_cat_str(i);
857
 
        else if(name==String("genmenu"))
858
 
          genmenu=get_eq_cat_str(i);    
859
 
        else if(name==String("postrun"))
860
 
          postrun=get_eq_cat_str(i);    
861
 
        else if(name==String("prerun"))
862
 
          prerun=get_eq_cat_str(i);     
863
 
        else if(name==String("preruntest"))
864
 
          preruntest=get_eq_cat_str(i); 
865
 
        else if(name==String("onlyrunasroot"))
866
 
          onlyrunasroot=i.get_eq_boolean();     
867
 
        else if(name==String("onlyrunasuser"))
868
 
          onlyrunasuser=i.get_eq_boolean();     
869
 
        else if(name==String("sort"))
870
 
          sort=get_eq_cat_str(i);
871
 
 
872
 
        else if(name==String("compat")){
873
 
          compt=i.get_eq_Stringconst();
874
 
          if(compt==String("menu-1"))
875
 
            i.seteolmode(parsestream::eol_newline);
876
 
          else if(compt==String("menu-2"))
877
 
            i.seteolmode(parsestream::eol_semicolon);
878
 
          else 
879
 
            throw unknown_compat(&i, compt);
880
 
        }
881
 
        else if(name==String("rcfile"))
882
 
          rcf=i.get_eq_Stringconst();
883
 
        else if(name==String("examplercfile"))
884
 
          exrcf=i.get_eq_Stringconst();
885
 
        else if(name==String("mainmenutitle"))
886
 
          mainmt=i.get_eq_Stringconst();
887
 
        else if(name==String("rootsection"))
888
 
          roots=i.get_eq_Stringconst();
889
 
        else if(name==String("rootprefix"))
890
 
          rootpref=i.get_eq_Stringconst();
891
 
        else if(name==String("userprefix"))
892
 
          userpref=i.get_eq_Stringconst();
893
 
        else if(name==String("treewalk"))
894
 
          treew=i.get_eq_Stringconst();
895
 
        else if(name==String("postoutput"))
896
 
          postout=i.get_eq_Stringconst();
897
 
        else if(name==String("preoutput"))
898
 
          preout=i.get_eq_Stringconst();
899
 
        else if(name==String("command")){
900
 
          system((i.get_eq_Stringconst()).c_str());
901
 
          exit(0);
902
 
        }
903
 
        else if(name==String("hotkeycase")){
904
 
          String s=i.get_eq_Stringconst();
905
 
          if(s==String("sensitive"))
906
 
            hotkeycase=1;
907
 
          else if (s==String("insensitive"))
908
 
            hotkeycase=0;
909
 
          else {
910
 
            cerr<<"install-menus hotkeycase can only be {,in}sensitive"<<endl;
911
 
            throw informed_fatal();
912
 
          }
913
 
        } 
914
 
        else if(name==String("hint_optimize"))
915
 
          hint_optimize=i.get_eq_boolean();
916
 
        else if(name==String("hint_nentry"))
917
 
          hint_nentry=i.get_eq_double();
918
 
        else if(name==String("hint_topnentry"))
919
 
          hint_topnentry=i.get_eq_integer();
920
 
        else if(name==String("hint_mixedpenalty"))
921
 
          hint_mixedpenalty=i.get_eq_double();
922
 
        else if(name==String("hint_minhintfreq"))
923
 
          hint_minhintfreq=i.get_eq_double();
924
 
        else if(name==String("hint_mlpenalty"))
925
 
          hint_mlpenalty=i.get_eq_double();
926
 
        else if(name==String("hint_max_ntry")){
927
 
          hint_max_ntry=i.get_eq_integer();
928
 
          if(hint_max_ntry < 1)
929
 
            hint_max_ntry=1;
930
 
        }
931
 
        else if(name==String("hint_max_iter_hint"))
932
 
          hint_max_iter_hint=i.get_eq_integer();
933
 
        else if(name==String("hint_debug"))
934
 
          hint_debug=i.get_eq_boolean();
935
 
        else
936
 
          throw unknown_ident(&i);
937
 
      i.skip_line();//read away final newline
938
 
    }
939
 
  }
940
 
  catch(endoffile){}
941
 
  
942
 
  check_config();
943
 
}
944
 
void configinfo::check_config(){
945
 
  if(!(genmenu && startmenu && endmenu)){
946
 
    cerr<<"At least one of genmenu, startmenu, endmenu"<<endl
947
 
        <<"is undefined in the config file. All of these have to be "<<endl
948
 
        <<"defined (although they may be equal to \"\")"<<endl;
949
 
    throw informed_fatal();
950
 
  }
951
 
}
952
 
String configinfo::prefix(){
953
 
  String s;
954
 
 
955
 
  if(getuid())
956
 
    return String(getenv("HOME"))+"/"+userprefix();
957
 
  else
958
 
    return rootpref;
959
 
}
960
 
 
961
 
ostream &configinfo::debuginfo(ostream &o){
962
 
    o<<"Using compatibility with:"<<compt<<endl
963
 
     <<"mainmenutitle   : "<<mainmt   <<endl
964
 
     <<"rootsection     : "<<roots    <<endl
965
 
     <<"rcfile          : "<<rcf      <<endl
966
 
     <<"examplercfile   : "<<exrcf    <<endl
967
 
     <<"root-prefix     : "<<rootpref <<endl
968
 
     <<"user-prefix     : "<<userpref <<endl
969
 
     <<"startmenu       : "<<endl;
970
 
    if(startmenu)
971
 
      startmenu->debuginfo(o);
972
 
    o<<"endmenu         : "<<endl;
973
 
    if(endmenu)
974
 
      endmenu->debuginfo(o);
975
 
    o<<"genmenu         : "<<endl;
976
 
    if(genmenu)
977
 
      genmenu->debuginfo(o);
978
 
    o<<"submenutitle    : "<<endl;
979
 
    if(submenutitle)
980
 
      submenutitle->debuginfo(o);
981
 
  o<<"mainmenutitle   : "<<mainmt   <<endl
982
 
   <<"treewalk        : "<<treew    <<endl;
983
 
  return o;
984
 
}
985
 
 
986
 
/////////////////////////////////////////////////////
987
 
//  Misc
988
 
//
989
 
 
990
 
map <String, String, less<String> > read_vars(parsestream &i){
991
 
  map <String, String, less<String> > m;
992
 
  try{
993
 
    String name, val;
994
 
    while(1){
995
 
      name=i.get_name();
996
 
      val=i.get_eq_Stringconst();
997
 
      m[name]=val;
998
 
    } 
999
 
  }
1000
 
  catch(endofline p){};
1001
 
  return m;
1002
 
}
1003
 
 
1004
 
void check_vars(parsestream &i,
1005
 
                map <String, String, less<String> > &m){
1006
 
  vector <String> need;
1007
 
  map <String, String, less<String> >::iterator j;
1008
 
  unsigned int k;
1009
 
 
1010
 
  need.push_back(SECTION_VAR);
1011
 
  need.push_back(TITLE_VAR);
1012
 
  need.push_back(NEEDS_VAR);
1013
 
 
1014
 
  for(k=0;k<need.size();k++){
1015
 
    j=m.find(need[k]);
1016
 
    if((j==m.end())||((*j).second==String("")))
1017
 
      throw missing_tag(&i,need[k]);
1018
 
  }
1019
 
}
1020
 
void read_input(parsestream &i){
1021
 
  String s;
1022
 
  try{
1023
 
    while(1){
1024
 
      map <String, String, less<String> > m;
1025
 
      StrVec sec_vec;
1026
 
      
1027
 
      m=read_vars(i);
1028
 
 
1029
 
      // check presence of section,title,needs vars. Later we will blindly
1030
 
      // assume they are defined.
1031
 
      check_vars(i,m);
1032
 
 
1033
 
      break_slashes(m[SECTION_VAR],sec_vec);
1034
 
      //if(m.find(SORT_VAR)!=m.end())
1035
 
      //        sec_vec.push_back(m[SORT_VAR]+":"+m[TITLE_VAR]);
1036
 
      //else
1037
 
      sec_vec.push_back(m[TITLE_VAR]);    
1038
 
      if(supported->prec(m[NEEDS_VAR])!=MAXINT)
1039
 
        menu.add_entry(sec_vec,m);
1040
 
      i.skip_line();   //read away the final newline
1041
 
    }
1042
 
  }
1043
 
  catch(endoffile p){}
1044
 
}
1045
 
 
1046
 
 
1047
 
void includemenus(String o, String i,
1048
 
                  String rep, String m){
1049
 
  //copy filename i to filename o, replacing the line
1050
 
  //rep with menu-file m
1051
 
  char buf[MAX_BUF];
1052
 
  char c;
1053
 
  bool changed=false;
1054
 
  ifstream fi(i.c_str());
1055
 
  ifstream fm(m.c_str());
1056
 
  
1057
 
  if(!fi){
1058
 
    cerr<<"Cannot open file "<<i<<endl; throw informed_fatal();}
1059
 
  if(!fm){
1060
 
    cerr<<"Cannot open file "<<m<<endl; throw informed_fatal();}
1061
 
 
1062
 
  ofstream fo(o.c_str());
1063
 
 
1064
 
  if(!fo){
1065
 
    cerr<<"Cannot open file "<<o<<endl; throw informed_fatal();}
1066
 
 
1067
 
  {
1068
 
    while(fi.get(buf,sizeof(buf))){
1069
 
      if(String(buf).contains(rep,0)){
1070
 
        while(fm.get(buf,sizeof(buf))){
1071
 
          fo<<buf<<endl;
1072
 
          fm.get(c);
1073
 
        }
1074
 
        changed=true;
1075
 
      }
1076
 
      else
1077
 
        fo<<buf<<endl;
1078
 
      fi.get(c);
1079
 
    }
1080
 
  }
1081
 
  if(!changed)
1082
 
    cerr<<"Warning: String \""<<rep
1083
 
        <<"\" didn't occur in example file "<<i<<endl;
1084
 
}
1085
 
 
1086
 
int main(int argc, char **argv){
1087
 
  int c, option_index;
1088
 
  char script[MAX_BUF];
1089
 
 
1090
 
  String menudefname;
1091
 
  
1092
 
  try{
1093
 
    if(argv[1])
1094
 
      strcpy(script, argv[1]);
1095
 
    else{
1096
 
      cerr<<"install-menu: First parameter must be name of script"<<endl;
1097
 
      throw informed_fatal();
1098
 
    }
1099
 
 
1100
 
    while(1){
1101
 
      c = getopt_long (argc, argv, "fdvh", long_options, &option_index);
1102
 
      if(c==-1) 
1103
 
        break;
1104
 
      switch(c){
1105
 
      case '?': 
1106
 
        cerr<<"Try  --help for more information.\n"<<endl;
1107
 
        throw informed_fatal();
1108
 
      case 'd': dodebug=1; break;
1109
 
      case 'v': verbose=1;break;
1110
 
      case 'h': usage(); break;
1111
 
      case 'f':break;
1112
 
      }
1113
 
    } while (c!=-1);
1114
 
 
1115
 
    add_functions();
1116
 
    parsestream ps(script);
1117
 
    if(!ps.good()){
1118
 
      cerr<<"Cannot open script "<<script<< " for reading"<<endl;
1119
 
      throw informed_fatal();
1120
 
    }
1121
 
    config=new configinfo(ps);
1122
 
    if(dodebug){
1123
 
      config->debuginfo(cerr);
1124
 
      supported->debuginfo(cerr);
1125
 
    }
1126
 
    if(config->prerun)
1127
 
      system((config->prerun->soutput(menu.vars)).c_str());
1128
 
    if(config->preruntest){
1129
 
      bool r;
1130
 
      r=system((config->preruntest->soutput(menu.vars)).c_str());
1131
 
      if(r)
1132
 
        return r;
1133
 
    }
1134
 
    if(config->onlyrunasroot)
1135
 
      if(getuid())
1136
 
        return 0;
1137
 
    if(config->onlyrunasuser)
1138
 
      if(!getuid())
1139
 
        return 0;
1140
 
    parsestream psscript(cin);
1141
 
    menu.vars[TITLE_VAR]=config->mainmenutitle();
1142
 
 
1143
 
    read_input(psscript);
1144
 
    if(config->hint_optimize){ 
1145
 
      StrVec v;
1146
 
      menu.process_hints(v);
1147
 
    };
1148
 
    menu.postprocess(1,0, config->rootsection());
1149
 
    menu.output();
1150
 
    closegenoutput();
1151
 
    if(config->rcfile().length()&&config->examplercfile().length())
1152
 
      includemenus(config->prefix()+"/"+config->rcfile(),
1153
 
                   config->prefix()+"/"+config->examplercfile(),
1154
 
                   "include-menu-defs",
1155
 
                   config->prefix()+"/"+config->genmenu->soutput(menu.vars));
1156
 
    if(config->postrun)
1157
 
      system((config->postrun->soutput(menu.vars)).c_str());
1158
 
    exit(0);
1159
 
  }
1160
 
  //yes, I know this _should_ be handled in one
1161
 
  //"derived" exception handler, but gcc doesn't like those
1162
 
  // (I'm getting internal compiler errors now quite often
1163
 
  // already, and I remember having them even more frequenly
1164
 
  // with the -frtty stuff -- _I_WANT_gcc-2.8_!).
1165
 
  catch(endoffile p){        p.report(cerr); }
1166
 
  catch(endofline p){        p.report(cerr); }
1167
 
  catch(char_expected p){    p.report(cerr); }
1168
 
  catch(char_unexpected p){  p.report(cerr); }
1169
 
  catch(unexpectedtrailing p){p.report(cerr);}
1170
 
  catch(boolean_expected p){ p.report(cerr); }
1171
 
  catch(ident_expected p){   p.report(cerr); }
1172
 
  catch(narg_mismatch p){    p.report(cerr); }
1173
 
  catch(unknown_function p){ p.report(cerr); }
1174
 
  catch(unknown_ident p){    p.report(cerr); }
1175
 
  catch(ferror_open p){      p.report(cerr); }
1176
 
  catch(missing_tag p){      p.report(cerr); }
1177
 
  catch(unknown_compat p){   p.report(cerr); }
1178
 
 
1179
 
  catch(dir_createerror d){
1180
 
    cerr<<": Cannot create directory "<<d.name<<endl;
1181
 
  }
1182
 
  catch(informed_fatal){};
1183
 
 
1184
 
  cerr<<script<<": Aborting"<<endl;
1185
 
 
1186
 
  exit(1);
1187
 
}