Subversion Repositories oidplus

Rev

Rev 747 | Rev 749 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
733 daniel-mar 1
program OIDPLUS;
2
 
3
(************************************************)
4
(* OIDPLUS.PAS                                  *)
5
(* Author:   Daniel Marschall                   *)
748 daniel-mar 6
(* Revision: 2022-02-19                         *)
733 daniel-mar 7
(* License:  Apache 2.0                         *)
8
(* This file contains:                          *)
9
(* - "OIDplus for DOS" program                  *)
10
(************************************************)
11
 
741 daniel-mar 12
(* IMPORTANT:                                                  *)
13
(* When you compile this code with Turbo Pascal 7.01,          *)
14
(* it won't run on fast PCs (Runtime Error 200).               *)
15
(* The built EXE file needs to be patched.                     *)
16
(* The program "PatchCRT" by Kennedy Software                  *)
17
(* WON'T work because it somehow breaks our "_Pause" function. *)
18
(* Instead, use the tool "TPPATCH" by Andreas Bauer.           *)
19
 
733 daniel-mar 20
uses
748 daniel-mar 21
  Dos, Crt, Drivers, StrList, VtsFuncs, VtsCui, OidFile, OidUtils,
22
  Weid;
733 daniel-mar 23
 
24
const
748 daniel-mar 25
  VERSIONINFO            = 'Revision: 2022-02-19';
735 daniel-mar 26
  DEFAULT_STATUSBAR      = '(C)2020-2022 ViaThinkSoft. Licensed under the terms of the Apache 2.0 license.';
740 daniel-mar 27
  TITLEBAR_LEFT_TEXT     = 'OIDplus';
733 daniel-mar 28
  DISKIO_SOUND_DEBUGGING = false;
735 daniel-mar 29
  DISKIO_SOUND_DELAY     = 500;
30
  ASNEDIT_LINES          = 10;
31
  DESCEDIT_LINES         = 10;
32
  DESCEDIT_PADDING       = 3;
33
  ACTIONMENU_SIZE        = 5;
34
  MAINMENU_WIDTH         = 15;
35
  MAINMENU_HEIGHT        = 3;
36
  MAINMENU_ALLOW_ESC     = false;
740 daniel-mar 37
  TREEVIEW_INDENT        = 0;
38
  TREEVIEW_INCLUDE_DESC  = true;
39
  TREEVIEW_WIDTH         = 80;
744 daniel-mar 40
  OID_EXTENSION          = '.OID';
41
  TREEVIEW_FILENAME      = 'OIDTREE.TXT';
733 daniel-mar 42
 
743 daniel-mar 43
procedure _Pause;
733 daniel-mar 44
begin
743 daniel-mar 45
  DrawStatusBar('Press any key to continue');
746 daniel-mar 46
  CursorOn;
743 daniel-mar 47
  ReadKey;
746 daniel-mar 48
  CursorOff;
743 daniel-mar 49
  DrawStatusBar(DEFAULT_STATUSBAR);
50
end;
51
 
52
function _WriteOidFile(filename: string; oid: POid; ShowErrorMessage: boolean): boolean;
53
var
54
  res: boolean;
55
begin
733 daniel-mar 56
  DrawStatusBar('Write file ' + filename + '...');
743 daniel-mar 57
  res := WriteOidFile(filename, oid);
733 daniel-mar 58
  if DISKIO_SOUND_DEBUGGING then
59
  begin
60
    Sound(70);
61
    Delay(DISKIO_SOUND_DELAY - 10);
62
    NoSound;
63
    Delay(10);
64
  end;
743 daniel-mar 65
  DrawStatusBar(DEFAULT_STATUSBAR);
733 daniel-mar 66
 
743 daniel-mar 67
  _WriteOidFile := res;
68
 
69
  if ShowErrorMessage and not res then
70
  begin
71
    ShowMessage('Cannot write to file ' + filename, 'ERROR', true);
72
    _Pause;
73
  end;
733 daniel-mar 74
end;
75
 
743 daniel-mar 76
function _ReadOidFile(filename: string; oid: POid; ShowErrorMessage: boolean): boolean;
77
var
78
  res: boolean;
733 daniel-mar 79
begin
80
  DrawStatusBar('Read file ' + filename + '...');
743 daniel-mar 81
  res := ReadOidFile(filename, oid);
733 daniel-mar 82
  if DISKIO_SOUND_DEBUGGING then
83
  begin
84
    Sound(50);
85
    Delay(DISKIO_SOUND_DELAY - 10);
86
    NoSound;
87
    Delay(10);
88
  end;
89
  DrawStatusBar(DEFAULT_STATUSBAR);
90
 
743 daniel-mar 91
  _ReadOidFile := res;
92
 
93
  if ShowErrorMessage and not res then
94
  begin
95
    ShowMessage('Cannot read file ' + filename, 'ERROR', true);
96
    _Pause;
97
  end;
733 daniel-mar 98
end;
99
 
740 daniel-mar 100
function _ShowASNIds(childOID: POID): string;
733 daniel-mar 101
var
102
  j, jmax: integer;
103
  sTmp: string;
104
begin
105
  sTmp := '';
735 daniel-mar 106
  jmax := ListCount(childOID^.ASNIds)-1;
733 daniel-mar 107
  for j := 0 to jmax do
108
  begin
109
    if j = 0 then sTmp := sTmp + ' (';
735 daniel-mar 110
    sTmp := sTmp + ListGetElement(childOID^.ASNIds, j);
733 daniel-mar 111
    if j = jmax then
112
      sTmp := sTmp + ')'
113
    else
114
      sTmp := sTmp + ', ';
115
  end;
116
  _ShowASNIds := sTmp;
117
end;
118
 
119
function AsnAlreadyExisting(oid: POID; asnid: string): boolean;
120
begin
741 daniel-mar 121
  AsnAlreadyExisting := ListContains(oid^.AsnIds, asnid);
733 daniel-mar 122
end;
123
 
124
function AsnEditor(oid: POID): boolean;
125
var
126
  asnList: PStringList;
127
  i: integer;
128
  x, y, w, h: integer;
129
  res: integer;
130
  sInput: string;
735 daniel-mar 131
  menuIdNew, menuIdSave, menuIdExit: integer;
733 daniel-mar 132
begin
133
  AsnEditor := false;
134
 
135
  repeat
735 daniel-mar 136
    CreateList(asnList);
733 daniel-mar 137
 
138
    for i := 0 to ListCount(oid^.ASNIds)-1 do
139
    begin
140
      ListAppend(asnList, ListGetElement(oid^.ASNIDs, i));
141
    end;
735 daniel-mar 142
    menuIdNew  := ListAppend(asnList, '<NEW>');
143
    menuIdSave := ListAppend(asnList, '<SAVE>');
144
    menuIdExit := ListAppend(asnList, '<CANCEL>');
733 daniel-mar 145
 
146
    DrawStatusBar(DEFAULT_STATUSBAR);
147
    x := SINGLE_LINE_BOX_PADDING;
148
    y := ScreenHeight div 2 - ASNEDIT_LINES div 2;
149
    w := ScreenWidth - (SINGLE_LINE_BOX_PADDING-1)*2;
150
    h := ASNEDIT_LINES;
151
    res := DrawSelectionList(x, y, w, h,
152
                             asnList, true,
153
                             'EDIT ASN.1 IDENTIFIERS',
154
                             2);
735 daniel-mar 155
    FreeList(asnList);
733 daniel-mar 156
 
157
    (* Change double-border to thin-border *)
158
    DrawThinBorder(x-1, y-1, w+2, h+2);
159
    GoToXY(x+1, y-1);
160
    Write('EDIT ASN.1 IDENTIFIERS');
161
 
162
    if res = -1 then
163
    begin
164
      exit;
165
    end
735 daniel-mar 166
    else if res = menuIdNew then
733 daniel-mar 167
    begin
168
      (* "NEW" item was selected *)
169
      sInput := '';
746 daniel-mar 170
      CursorOn;
733 daniel-mar 171
      repeat
172
        if QueryVal(sInput,
173
                    SINGLE_LINE_BOX_PADDING_INNER,
174
                    ScreenHeight div 2,
175
                    ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
176
                    1,
177
                    'ADD SINGLE ASN.1 ID',
178
                    2) then
179
        begin
180
          if sInput = '' then continue;
181
          if not ASN1IDValid(sInput) then
182
          begin
183
            ShowMessage('Invalid ASN1.ID! (Require -, a..z, A..Z, 0..9, begin with a-z)', 'ERROR', true);
184
            _Pause;
185
          end
186
          else if AsnAlreadyExisting(oid, sInput) then
187
          begin
188
            ShowMessage('ASN.1 identifier is already existing on this arc', 'ERROR', true);
189
            _Pause;
190
          end
191
          else
192
          begin
193
            ListAppend(oid^.ASNIDs, sInput);
194
            break;
195
          end;
196
        end
197
        else break;
198
      until false;
746 daniel-mar 199
      CursorOff;
733 daniel-mar 200
    end
735 daniel-mar 201
    else if res = menuIdSave then
733 daniel-mar 202
    begin
203
      (* "SAVE" item was selected *)
204
      AsnEditor := true;
205
      Exit;
206
    end
735 daniel-mar 207
    else if res = menuIdExit then
733 daniel-mar 208
    begin
209
      (* "CANCEL" item was selected *)
210
      AsnEditor := false;
211
      Exit;
212
    end
213
    else
214
    begin
215
      DrawStatusBar('Note: Remove the text to delete the ASN.1 identifier');
216
      sInput := ListGetElement(oid^.ASNIDs, res);
746 daniel-mar 217
          CursorOn;
733 daniel-mar 218
      repeat
219
        if QueryVal(sInput,
220
                    SINGLE_LINE_BOX_PADDING_INNER,
221
                    ScreenHeight div 2,
222
                    ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
223
                    1,
224
                    'EDIT SINGLE ASN.1 ID',
225
                    2) then
226
        begin
227
          if sInput = '' then
228
          begin
229
            (* Empty input = Delete ASN.1 ID *)
737 daniel-mar 230
            ListDeleteElementByIndex(oid^.ASNIDs, res);
733 daniel-mar 231
            break;
232
          end
233
          else if not ASN1IDValid(sInput) then
234
          begin
235
            ShowMessage('Invalid ASN1.ID! (Require -, a..z, A..Z, 0..9, begin with a-z)', 'ERROR', true);
236
            _Pause;
237
          end
238
          else if AsnAlreadyExisting(oid, sInput) and
239
              not (ListGetElement(oid^.ASNIDs, res) = sInput) then
240
          begin
241
            ShowMessage('ASN.1 identifier is already existing on this arc', 'ERROR', true);
242
            _Pause;
243
          end
244
          else
245
          begin
246
            ListSetElement(oid^.ASNIDs, res, sInput);
247
            break;
248
          end;
249
        end
250
        else break;
251
      until false;
746 daniel-mar 252
          CursorOff;
733 daniel-mar 253
    end;
254
  until false;
255
end;
256
 
748 daniel-mar 257
function UnicodeLabelAlreadyExisting(oid: POID; unicodeLabel: string): boolean;
258
begin
259
  UnicodeLabelAlreadyExisting := ListContains(oid^.UnicodeLabels, unicodeLabel);
260
end;
261
 
262
function IriEditor(oid: POID): boolean;
263
var
264
  iriList: PStringList;
265
  i: integer;
266
  x, y, w, h: integer;
267
  res: integer;
268
  sInput: string;
269
  menuIdNew, menuIdSave, menuIdExit: integer;
270
begin
271
  IriEditor := false;
272
 
273
  repeat
274
    CreateList(iriList);
275
 
276
    for i := 0 to ListCount(oid^.UnicodeLabels)-1 do
277
    begin
278
      ListAppend(iriList, ListGetElement(oid^.UnicodeLabels, i));
279
    end;
280
    menuIdNew  := ListAppend(iriList, '<NEW>');
281
    menuIdSave := ListAppend(iriList, '<SAVE>');
282
    menuIdExit := ListAppend(iriList, '<CANCEL>');
283
 
284
    DrawStatusBar(DEFAULT_STATUSBAR);
285
    x := SINGLE_LINE_BOX_PADDING;
286
    y := ScreenHeight div 2 - ASNEDIT_LINES div 2;
287
    w := ScreenWidth - (SINGLE_LINE_BOX_PADDING-1)*2;
288
    h := ASNEDIT_LINES;
289
    res := DrawSelectionList(x, y, w, h,
290
                             iriList, true,
291
                             'EDIT UNICODE LABELS',
292
                             2);
293
    FreeList(iriList);
294
 
295
    (* Change double-border to thin-border *)
296
    DrawThinBorder(x-1, y-1, w+2, h+2);
297
    GoToXY(x+1, y-1);
298
    Write('EDIT UNICODE LABELS');
299
 
300
    if res = -1 then
301
    begin
302
      exit;
303
    end
304
    else if res = menuIdNew then
305
    begin
306
      (* "NEW" item was selected *)
307
      sInput := '';
308
      CursorOn;
309
      repeat
310
        if QueryVal(sInput,
311
                    SINGLE_LINE_BOX_PADDING_INNER,
312
                    ScreenHeight div 2,
313
                    ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
314
                    1,
315
                    'ADD SINGLE UNICODE LABEL',
316
                    2) then
317
        begin
318
          if sInput = '' then continue;
319
          if not UnicodeLabelValid(sInput) then
320
          begin
321
            ShowMessage('Invalid Unicode Label!', 'ERROR', true);
322
            _Pause;
323
          end
324
          else if UnicodeLabelAlreadyExisting(oid, sInput) then
325
          begin
326
            ShowMessage('Unicode Label is already existing on this arc', 'ERROR', true);
327
            _Pause;
328
          end
329
          else
330
          begin
331
            ListAppend(oid^.UnicodeLabels, sInput);
332
            break;
333
          end;
334
        end
335
        else break;
336
      until false;
337
      CursorOff;
338
    end
339
    else if res = menuIdSave then
340
    begin
341
      (* "SAVE" item was selected *)
342
      IriEditor := true;
343
      Exit;
344
    end
345
    else if res = menuIdExit then
346
    begin
347
      (* "CANCEL" item was selected *)
348
      IriEditor := false;
349
      Exit;
350
    end
351
    else
352
    begin
353
      DrawStatusBar('Note: Remove the text to delete the Unicode Label');
354
      sInput := ListGetElement(oid^.UnicodeLabels, res);
355
          CursorOn;
356
      repeat
357
        if QueryVal(sInput,
358
                    SINGLE_LINE_BOX_PADDING_INNER,
359
                    ScreenHeight div 2,
360
                    ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
361
                    1,
362
                    'EDIT SINGLE UNICODE LABEL',
363
                    2) then
364
        begin
365
          if sInput = '' then
366
          begin
367
            (* Empty input = Delete Unicode label *)
368
            ListDeleteElementByIndex(oid^.UnicodeLabels, res);
369
            break;
370
          end
371
          else if not UnicodeLabelValid(sInput) then
372
          begin
373
            ShowMessage('Invalid Unicode Label!', 'ERROR', true);
374
            _Pause;
375
          end
376
          else if UnicodeLabelAlreadyExisting(oid, sInput) and
377
              not (ListGetElement(oid^.UnicodeLabels, res) = sInput) then
378
          begin
379
            ShowMessage('Unicode Label is already existing on this arc', 'ERROR', true);
380
            _Pause;
381
          end
382
          else
383
          begin
384
            ListSetElement(oid^.UnicodeLabels, res, sInput);
385
            break;
386
          end;
387
        end
388
        else break;
389
      until false;
390
          CursorOff;
391
    end;
392
  until false;
393
end;
394
 
733 daniel-mar 395
function DescEditor(oid: POID): boolean;
396
var
397
  sInput: string;
398
begin
399
  DescEditor := false;
400
 
401
  DrawStatusBar('Note: Press Ctrl+Return for a line-break.');
402
  sInput := oid^.description;
746 daniel-mar 403
  CursorOn;
733 daniel-mar 404
  if QueryVal(sInput,
405
              DESCEDIT_PADDING,
406
              ScreenHeight div 2 - DESCEDIT_LINES div 2,
407
              ScreenWidth - (DESCEDIT_PADDING-1)*2,
408
              DESCEDIT_LINES,
409
              'EDIT DESCRIPTION',
410
              2) then
411
  begin
412
    oid^.description := sInput;
740 daniel-mar 413
    DescEditor := true; (* request caller to save <oid> *)
733 daniel-mar 414
  end;
746 daniel-mar 415
  CursorOff;
733 daniel-mar 416
end;
417
 
418
function NextPossibleFileID: string;
419
var
420
  DirInfo: SearchRec;
421
  list: PStringList;
422
  iId: LongInt;
423
  sId: string;
424
begin
425
  (* Put all found files into a list *)
735 daniel-mar 426
  CreateList(list);
744 daniel-mar 427
  FindFirst(RepeatStr('?',8)+OID_EXTENSION, Archive, DirInfo);
733 daniel-mar 428
  while DosError = 0 do
429
  begin
430
    sId := Copy(DirInfo.Name, 1, 8);
431
    ListAppend(list, sId);
432
    FindNext(DirInfo);
433
  end;
434
 
435
  (* Search for the first non existing item in the list *)
436
  sId := '';
437
  for iId := 0 to 99999999 do
438
  begin
439
    sId := ZeroPad(iId, 8);
440
    if not ListContains(list, sId) then break;
441
  end;
442
  NextPossibleFileId := sId;
443
  FreeList(list);
444
end;
445
 
446
function NumIdAlreadyExisting(parentOID: POID; sInput: string): boolean;
447
var
448
  searchDotNotation: string;
449
  sTmp: string;
450
  i: integer;
451
begin
452
  if parentOID^.DotNotation = '' then
453
    searchDotNotation := sInput
454
  else
455
    searchDotNotation := parentOID^.DotNotation + '.' + sInput;
456
  for i := 0 to ListCount(parentOID^.SubIds)-1 do
457
  begin
458
    sTmp := ListGetElement(parentOID^.SubIds, i);
735 daniel-mar 459
    if DotNotationPart(sTmp) = searchDotNotation then
733 daniel-mar 460
    begin
461
      NumIdAlreadyExisting := true;
462
      exit;
463
    end;
464
  end;
465
  NumIdAlreadyExisting := false;
466
end;
467
 
468
function NumIdEditor(oid: POID; parentOID: POID): boolean;
469
var
470
  sInput: string;
471
begin
472
  NumIdEditor := false;
473
  sInput := '';
474
 
746 daniel-mar 475
  CursorOn;
733 daniel-mar 476
  repeat
477
    if QueryVal(sInput,
478
                SINGLE_LINE_BOX_PADDING_INNER,
479
                ScreenHeight div 2,
480
                ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
481
                1,
482
                'ENTER NUMERIC ID',
483
                2) then
484
    begin
485
      if sInput = '' then continue;
747 daniel-mar 486
      if not IsPositiveIntegerOrZero(sInput) then
733 daniel-mar 487
      begin
488
        ShowMessage('Invalid numeric ID (must be a positive integer)', 'ERROR', true);
489
        _Pause;
490
      end
491
      else if (parentOID^.DotNotation='') and (StrToInt(sInput) > 2) then
492
      begin
493
        ShowMessage('Invalid numeric ID (root arc can only be 0, 1, or 2)', 'ERROR', true);
494
        _Pause;
495
      end
496
      else if ((parentOID^.DotNotation='0') or (parentOID^.DotNotation='1')) and (StrToInt(sInput) > 39) then
497
      begin
498
        ShowMessage('Invalid numeric ID (root 0 and 1 must have sub-arc of 0..39)', 'ERROR', true);
499
        _Pause;
500
      end
501
      else if NumIdAlreadyExisting(parentOID, sInput) then
502
      begin
503
        ShowMessage('This numeric ID is already used in this arc', 'ERROR', true);
504
        _Pause;
505
      end
506
      else
507
      begin
508
        if parentOID^.DotNotation = '' then
509
          oid^.DotNotation := sInput
510
        else
511
          oid^.DotNotation := parentOID^.DotNotation + '.' + sInput;
740 daniel-mar 512
        NumIdEditor := true; (* request caller to save <oid> *)
746 daniel-mar 513
        Break;
733 daniel-mar 514
      end;
515
    end
516
    else
517
    begin
746 daniel-mar 518
      Break;
733 daniel-mar 519
    end;
520
  until false;
746 daniel-mar 521
  CursorOff;
733 daniel-mar 522
end;
523
 
524
function NewOidEditor(oid: POID): boolean;
525
var
526
  newfilename: string;
735 daniel-mar 527
  newOID: POID;
733 daniel-mar 528
begin
529
  NewOidEditor := false;
530
 
735 daniel-mar 531
  CreateOidDef(newOID);
532
  newOID^.FileId := NextPossibleFileID;
745 daniel-mar 533
  newOID^.ParentFileId := oid^.FileId;
534
  newOID^.ParentDotNotation := oid^.DotNotation;
735 daniel-mar 535
  if NumIdEditor(newOID, oid) and
536
     AsnEditor(newOID) and
748 daniel-mar 537
     IriEditor(newOID) and
735 daniel-mar 538
     DescEditor(newOID) then
734 daniel-mar 539
  begin
744 daniel-mar 540
    newfilename := newOID^.FileId + OID_EXTENSION;
743 daniel-mar 541
    if _WriteOidFile(newfilename, newOID, true) then
542
    begin
543
      (* Add link to original file and enable the saving of it *)
544
      ListAppend(oid^.SubIds, newOID^.FileId + newOID^.DotNotation);
545
      NewOidEditor := true; (* request caller to save <oid> *)
546
    end;
734 daniel-mar 547
  end;
735 daniel-mar 548
  FreeOidDef(newOID);
733 daniel-mar 549
end;
550
 
551
procedure DeleteChildrenRecursive(oid: POID);
552
var
553
  i: integer;
735 daniel-mar 554
  childOID: POID;
733 daniel-mar 555
  filenameChild: string;
556
begin
557
  for i := 0 to ListCount(oid^.SubIds)-1 do
558
  begin
744 daniel-mar 559
    filenameChild := FileIdPart(ListGetElement(oid^.SubIds, i)) + OID_EXTENSION;
740 daniel-mar 560
    if FileExists(filenameChild) then
561
    begin
562
      CreateOidDef(childOID);
744 daniel-mar 563
      if _ReadOidFile(filenameChild, childOID, false) and
745 daniel-mar 564
         (childOID^.ParentFileId = oid^.FileId) and
565
         (childOID^.ParentDotNotation = oid^.DotNotation) then
743 daniel-mar 566
      begin
567
        DeleteChildrenRecursive(childOID);
568
      end;
740 daniel-mar 569
      FreeOidDef(childOID);
570
      DeleteFile(filenameChild);
571
    end;
733 daniel-mar 572
  end;
573
  ListClear(oid^.SubIds);
574
end;
575
 
576
procedure DeleteOidRecursive(selfOID: POID);
577
var
578
  i: integer;
735 daniel-mar 579
  parentOID: POID;
733 daniel-mar 580
  filenameSelf, filenameParent: string;
581
begin
582
  (* Remove all children and their files recursively *)
583
  DeleteChildrenRecursive(selfOID);
584
 
585
  (* Remove forward reference in parent OID *)
743 daniel-mar 586
  (* (this is the most important part)      *)
745 daniel-mar 587
  filenameParent := selfOID^.ParentFileId + OID_EXTENSION;
740 daniel-mar 588
  if FileExists(filenameParent) then
733 daniel-mar 589
  begin
740 daniel-mar 590
    CreateOidDef(parentOID);
743 daniel-mar 591
    if _ReadOidFile(filenameParent, parentOID, true) then
740 daniel-mar 592
    begin
743 daniel-mar 593
      if ListDeleteElementByValue(parentOID^.SubIds, selfOID^.FileId + selfOID^.DotNotation) then
594
      begin
595
        _WriteOidFile(filenameParent, parentOID, true);
596
      end;
740 daniel-mar 597
    end;
598
    FreeOidDef(parentOID);
733 daniel-mar 599
  end;
600
 
601
  (* Delete own file *)
744 daniel-mar 602
  filenameSelf := selfOID^.FileId + OID_EXTENSION;
740 daniel-mar 603
  if FileExists(filenameSelf) then
604
  begin
605
    DeleteFile(filenameSelf);
606
  end;
733 daniel-mar 607
end;
608
 
735 daniel-mar 609
function _DeleteConfirmation: boolean;
610
var
611
  sc: Char;
612
begin
613
  repeat
614
    ShowMessage('Are you sure you want to delete this OID? (Y/N)', 'DELETE OID', true);
737 daniel-mar 615
    DrawStatusBar('Y=Yes, N=No');
735 daniel-mar 616
 
746 daniel-mar 617
    CursorOn;
735 daniel-mar 618
    sc := ReadKey;
746 daniel-mar 619
    CursorOff;
735 daniel-mar 620
    if sc = #0 then
621
    begin
622
      (* Extended key. Nothing we care about. *)
623
      ReadKey;
624
      continue;
625
    end;
626
 
627
    if UpCase(sc) = 'Y' then
628
    begin
629
      _DeleteConfirmation := true;
630
      break;
737 daniel-mar 631
    end
632
    else if UpCase(sc) = 'N' then
735 daniel-mar 633
    begin
634
      _DeleteConfirmation := false;
635
      break;
636
    end;
637
  until false;
638
end;
639
 
737 daniel-mar 640
procedure _DrawOidTitleBar(filename: string; oid: POID);
641
begin
642
  if oid^.DotNotation = '' then
738 daniel-mar 643
    DrawTitleBar('OID ROOT', TITLEBAR_LEFT_TEXT, filename)
737 daniel-mar 644
  else
738 daniel-mar 645
    DrawTitleBar('OID ' + oid^.DotNotation, TITLEBAR_LEFT_TEXT, filename);
737 daniel-mar 646
end;
647
 
748 daniel-mar 648
function DotNotation(oid: POid): string;
649
var
650
  res: string;
651
begin
652
  res := oid^.DotNotation;
653
  if res = '' then res := '.'; (* root *)
654
  DotNotation := res;
655
end;
656
 
657
function OidLastArc(oid: POid): string;
658
var
659
  s: string;
660
  p: integer;
661
begin
662
  s := oid^.DotNotation;
663
 
664
  while true do
665
  begin
666
    p := Pos('.', s);
667
    if p = 0 then break;
668
    Delete(s, 1, p);
669
  end;
670
 
671
  OidLastArc := s;
672
end;
673
 
674
function AsnNotation(oid: POid): string;
675
var
676
  prevOid, curOid: POid;
677
  res: string;
678
begin
679
  CreateOidDef(curOid);
680
  prevOid := oid;
681
  res := '';
682
 
683
  while true do
684
  begin
685
    (* Note: BackRef is not checked yet! Infinite loop is possible! (TODO) *)
686
    ReadOidFile(prevOid^.ParentFileId + '.OID', curOid);
687
    if curOid^.ParentFileId = '' then break;
688
    if curOid^.ParentFileId = curOid^.FileId then break;
689
    if ListCount(curOid^.AsnIds) > 0 then
690
      res := ListGetElement(curOid^.AsnIds, 0) + '('+OidLastArc(curOid)+') ' + res
691
    else
692
      res := OidLastArc(curOid) + ' ' + res;
693
    prevOid := curOid;
694
  end;
695
  FreeOidDef(curOid);
696
  if ListCount(oid^.AsnIds) > 0 then
697
    res := res + ListGetElement(oid^.AsnIds, 0) + '('+OidLastArc(oid)+')'
698
  else
699
    res := res + OidLastArc(oid);
700
  if res = '' then
701
    AsnNotation := ''
702
  else
703
    AsnNotation := '{ ' + res + ' }';
704
end;
705
 
706
function IriNotation(oid: POid): string;
707
var
708
  prevOid, curOid: POid;
709
  res: string;
710
begin
711
  CreateOidDef(curOid);
712
  prevOid := oid;
713
  res := '';
714
 
715
  while true do
716
  begin
717
    (* Note: BackRef is not checked yet! Infinite loop is possible! (TODO) *)
718
    ReadOidFile(prevOid^.ParentFileId + '.OID', curOid);
719
    if curOid^.ParentFileId = '' then break;
720
    if curOid^.ParentFileId = curOid^.FileId then break;
721
    if ListCount(curOid^.UnicodeLabels) > 0 then
722
      res := ListGetElement(curOid^.UnicodeLabels, 0) + '/' + res
723
    else
724
      res := OidLastArc(curOid) + '/' + res;
725
    prevOid := curOid;
726
  end;
727
  FreeOidDef(curOid);
728
  if ListCount(oid^.UnicodeLabels) > 0 then
729
    res := res + ListGetElement(oid^.UnicodeLabels, 0)
730
  else
731
    res := res + OidLastArc(oid);
732
  IriNotation := '/' + res;
733
end;
734
 
735
function WeidNotation(oid: POid): string;
736
begin
737
  WeidNotation := OidToWeid(oid^.DotNotation);
738
end;
739
 
733 daniel-mar 740
procedure DisplayOIDFile(filename: string);
741
var
742
  isRoot: boolean;
740 daniel-mar 743
  oid, tmpOID: POID;
748 daniel-mar 744
  i: integer;
733 daniel-mar 745
  sTmp, subfile: string;
746
  subsel, subfiles: PStringList;
747
  subselres: integer;
735 daniel-mar 748
  exitRequest: boolean;
748 daniel-mar 749
  menuIdExit, menuIdAsnEdit, menuIdIriEdit, menuIdDescEdit, menuIdAdd, menuIdDelete: integer;
750
  menuX, menuY: integer;
733 daniel-mar 751
begin
735 daniel-mar 752
  exitRequest := false;
733 daniel-mar 753
  repeat
743 daniel-mar 754
    CreateOidDef(oid);
755
 
756
    if not _ReadOidFile(filename, oid, true) then
740 daniel-mar 757
    begin
743 daniel-mar 758
      FreeOidDef(oid);
740 daniel-mar 759
      exit;
760
    end;
761
 
733 daniel-mar 762
    (* Print OID information *)
763
 
764
    ClrScr;
737 daniel-mar 765
    _DrawOidTitleBar(filename, oid);
733 daniel-mar 766
    DrawStatusBar(DEFAULT_STATUSBAR);
767
    GotoXY(1,2);
768
 
748 daniel-mar 769
    (*if oid^.DotNotation <> '' then*)
733 daniel-mar 770
    begin
748 daniel-mar 771
      Write('Dot notation:   ');
772
      WriteLnKeepX(DotNotation(oid));
773
      Write('IRI notation:   ');
774
      WriteLnKeepX(IriNotation(oid));
775
      Write('ASN.1 notation: ');
776
      WriteLnKeepX(AsnNotation(oid));
777
      Write('WEID notation:  ');
778
      WriteLnKeepX(WeidNotation(oid));
733 daniel-mar 779
      WriteLn('');
780
    end;
781
 
735 daniel-mar 782
    if Trim(oid^.Description) <> '' then
733 daniel-mar 783
    begin
748 daniel-mar 784
      (* WriteLn('Description:'); *)
735 daniel-mar 785
      WriteLn(oid^.Description);
733 daniel-mar 786
      WriteLn('');
748 daniel-mar 787
    end
788
    else
733 daniel-mar 789
    begin
748 daniel-mar 790
      WriteLn('(No description has been added to this OID.)');
791
      WriteLn('');
733 daniel-mar 792
    end;
793
 
794
    (* Now prepare the menu entries *)
795
 
744 daniel-mar 796
    CreateList(subsel);   (* Contains the human-readable OID name *)
737 daniel-mar 797
    CreateList(subfiles); (* Contains the file name               *)
733 daniel-mar 798
 
745 daniel-mar 799
    if oid^.ParentFileId = '' then
733 daniel-mar 800
    begin
801
      isRoot := true;
802
    end
803
    else
804
    begin
745 daniel-mar 805
      isRoot := oid^.ParentDotNotation = oid^.DotNotation;
733 daniel-mar 806
    end;
807
 
745 daniel-mar 808
    if (oid^.ParentFileId <> '') and not isRoot then
733 daniel-mar 809
    begin
745 daniel-mar 810
      subfile := oid^.ParentFileId + OID_EXTENSION;
740 daniel-mar 811
      if FileExists(subfile) then
812
      begin
813
        CreateOidDef(tmpOID);
744 daniel-mar 814
        if not _ReadOidFile(subfile, tmpOID, true) then
815
        begin
745 daniel-mar 816
          ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + ' (READ ERROR)');
744 daniel-mar 817
          ListAppend(subfiles, 'ERROR: '+subfile+' Read error or file invalid');
818
        end
743 daniel-mar 819
        else
744 daniel-mar 820
        begin
745 daniel-mar 821
          ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + _ShowASNIds(tmpOID));
744 daniel-mar 822
          ListAppend(subfiles, subfile);
823
        end;
740 daniel-mar 824
        FreeOidDef(tmpOID);
825
      end
826
      else
827
      begin
745 daniel-mar 828
        ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + ' (FILE NOT FOUND)');
744 daniel-mar 829
        ListAppend(subfiles, 'ERROR: File '+subfile+' was not found');
740 daniel-mar 830
      end;
733 daniel-mar 831
    end;
832
 
833
    if isRoot then
834
    begin
735 daniel-mar 835
      menuIdExit := ListAppend(subsel, 'Back to main menu');
836
      ListAppend(subfiles, '');
837
    end
838
    else menuIdExit := -99;
733 daniel-mar 839
 
735 daniel-mar 840
    for i := 0 to ListCount(oid^.SubIds)-1 do
733 daniel-mar 841
    begin
735 daniel-mar 842
      sTmp := ListGetElement(oid^.SubIds, i);
744 daniel-mar 843
      subfile := FileIdPart(sTmp) + OID_EXTENSION;
740 daniel-mar 844
      if FileExists(subfile) then
845
      begin
846
        CreateOidDef(tmpOID);
744 daniel-mar 847
        if not _ReadOidFile(subfile, tmpOID, true) then
848
        begin
849
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (READ ERROR)');
850
          ListAppend(subfiles, 'ERROR: Read error at file '+subfile+', or file is invalid.');
851
        end
745 daniel-mar 852
        else if (tmpOID^.ParentFileId <> oid^.FileId) or
853
                (tmpOID^.ParentDotNotation <> oid^.DotNotation) then
744 daniel-mar 854
        begin
855
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (BAD BACKREF)');
856
          ListAppend(subfiles, 'ERROR: File '+subfile+' has a wrong back-reference.');
857
        end
743 daniel-mar 858
        else
744 daniel-mar 859
        begin
860
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + _ShowASNIds(tmpOID));
861
          ListAppend(subfiles, subfile);
862
        end;
740 daniel-mar 863
        FreeOidDef(tmpOID);
864
      end
865
      else
866
      begin
867
        ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (FILE NOT FOUND)');
744 daniel-mar 868
        ListAppend(subfiles, 'ERROR: File '+subfile+' was not found');
740 daniel-mar 869
      end;
733 daniel-mar 870
    end;
871
 
735 daniel-mar 872
    if oid^.DotNotation <> '' then
733 daniel-mar 873
    begin
748 daniel-mar 874
      menuIdAsnEdit := ListAppend(subsel, 'View/Edit ASN.1 identifiers');
735 daniel-mar 875
      ListAppend(subfiles, '');
876
    end
877
    else menuIdAsnEdit := -99;
733 daniel-mar 878
 
748 daniel-mar 879
    if oid^.DotNotation <> '' then
880
    begin
881
      menuIdIriEdit := ListAppend(subsel, 'View/Edit Unicode Labels');
882
      ListAppend(subfiles, '');
883
    end
884
    else menuIdIriEdit := -99;
885
 
735 daniel-mar 886
    menuIdDescEdit := ListAppend(subsel, 'Edit description');
887
    ListAppend(subfiles, '');
733 daniel-mar 888
 
735 daniel-mar 889
    menuIdAdd := ListAppend(subsel, 'Add child');
890
    ListAppend(subfiles, '');
733 daniel-mar 891
 
892
    if not isRoot then
893
    begin
735 daniel-mar 894
      menuIdDelete := ListAppend(subsel, 'Delete OID');
895
      ListAppend(subfiles, '');
896
    end
897
    else menuIdDelete := -99;
733 daniel-mar 898
 
734 daniel-mar 899
    (* Show menu *)
900
 
748 daniel-mar 901
    menuX := WhereX + 1;
902
    menuY := ScreenHeight - ACTIONMENU_SIZE - 1;
733 daniel-mar 903
    subselres := DrawSelectionList(menuX, menuY,
904
                                   ScreenWidth-2,
735 daniel-mar 905
                                   ACTIONMENU_SIZE,
733 daniel-mar 906
                                   subsel,
907
                                   true,
908
                                   'SELECT ACTION',
909
                                   1);
734 daniel-mar 910
 
911
    (* Process user selection *)
912
 
733 daniel-mar 913
    if subselres = -1 then
914
    begin
735 daniel-mar 915
      exitRequest := true;
733 daniel-mar 916
    end
735 daniel-mar 917
    else if subselres = menuIdAsnEdit then
733 daniel-mar 918
    begin
735 daniel-mar 919
      if AsnEditor(oid) then
743 daniel-mar 920
        _WriteOidFile(filename, oid, true);
735 daniel-mar 921
    end
748 daniel-mar 922
    else if subselres = menuIdIriEdit then
923
    begin
924
      if IriEditor(oid) then
925
        _WriteOidFile(filename, oid, true);
926
    end
735 daniel-mar 927
    else if subselres = menuIdDescEdit then
928
    begin
929
      if DescEditor(oid) then
743 daniel-mar 930
        _WriteOidFile(filename, oid, true);
735 daniel-mar 931
    end
932
    else if subselres = menuIdAdd then
933
    begin
934
      if NewOidEditor(oid) then
743 daniel-mar 935
        _WriteOidFile(filename, oid, true);
735 daniel-mar 936
    end
937
    else if subselres = menuIdDelete then
938
    begin
939
      if _DeleteConfirmation then
733 daniel-mar 940
      begin
745 daniel-mar 941
        sTmp := oid^.ParentFileId + OID_EXTENSION;
735 daniel-mar 942
        DeleteOidRecursive(oid);
740 daniel-mar 943
        if FileExists(sTmp) then
944
        begin
945
          filename := sTmp;
946
        end
947
        else
948
        begin
744 daniel-mar 949
          ShowMessage('Parent file ' + sTmp + ' was not found', 'ERROR', true);
740 daniel-mar 950
          _Pause;
951
          exitRequest := true;
952
        end;
733 daniel-mar 953
      end;
735 daniel-mar 954
    end
955
    else if subselres = menuIdExit then
956
    begin
957
      exitRequest := true;
958
    end
959
    else
960
    begin
961
      (* Normal OID *)
744 daniel-mar 962
      (* Above we already checked if the files are valild and existing *)
740 daniel-mar 963
      sTmp := ListGetElement(subfiles, subselres);
744 daniel-mar 964
      if Copy(sTmp, 1, Length('ERROR: ')) = 'ERROR: ' then
740 daniel-mar 965
      begin
744 daniel-mar 966
        Delete(sTmp, 1, Length('ERROR: '));
967
        ShowMessage(sTmp, 'ERROR', true);
968
        _Pause;
740 daniel-mar 969
      end
970
      else
971
      begin
744 daniel-mar 972
        filename := sTmp;
740 daniel-mar 973
      end;
733 daniel-mar 974
    end;
975
    FreeList(subsel);
976
    FreeList(subfiles);
977
 
735 daniel-mar 978
    FreeOidDef(oid);
979
  until exitRequest;
733 daniel-mar 980
end;
981
 
743 daniel-mar 982
function CreateRootOIDFile(filename: string; ShowErrorMessage: boolean): boolean;
733 daniel-mar 983
var
735 daniel-mar 984
  oid: POID;
733 daniel-mar 985
begin
735 daniel-mar 986
  CreateOidDef(oid);
745 daniel-mar 987
  oid^.Description  := 'This is the root of the OID tree.' +#13#10 +
988
                       #13#10 +
989
                       'Valid subsequent arcs are per definition:' + #13#10 +
990
                       '- 0 (itu-t)' + #13#10 +
991
                       '- 1 (iso)' + #13#10 +
992
                       '- 2 (joint-iso-itu-t)';
993
  oid^.FileId       := ZeroPad(0, 8);
994
  oid^.DotNotation  := '';
995
  oid^.ParentFileId := ZeroPad(0, 8);
996
  oid^.ParentDotNotation := '';
743 daniel-mar 997
  CreateRootOIDFile := _WriteOidFile(filename, oid, ShowErrorMessage);
735 daniel-mar 998
  FreeOidDef(oid);
733 daniel-mar 999
end;
1000
 
742 daniel-mar 1001
function _GetRootFile(ShowErrorMessage: boolean): string;
735 daniel-mar 1002
var
742 daniel-mar 1003
  rootFile: string;
733 daniel-mar 1004
begin
744 daniel-mar 1005
  rootFile := ZeroPad(0, 8) + OID_EXTENSION;
743 daniel-mar 1006
  _GetRootFile := rootFile;
742 daniel-mar 1007
  if not FileExists(rootFile) then
733 daniel-mar 1008
  begin
743 daniel-mar 1009
    if not CreateRootOIDFile(rootFile, ShowErrorMessage) then
742 daniel-mar 1010
    begin
743 daniel-mar 1011
      _GetRootFile := '';
742 daniel-mar 1012
    end;
1013
  end;
733 daniel-mar 1014
end;
1015
 
740 daniel-mar 1016
procedure OP_ManageOIDs;
742 daniel-mar 1017
var
1018
  rootfile: string;
740 daniel-mar 1019
begin
1020
  ClrScr;
1021
  DrawTitleBar('Manage Object Identifiers', TITLEBAR_LEFT_TEXT, '');
1022
  DrawStatusBar('Loading data... please wait...');
1023
 
742 daniel-mar 1024
  (* This will try creating a new root file if it does not exist *)
1025
  rootfile := _GetRootFile(true);
1026
  if rootfile = '' then Exit;
1027
 
1028
  DisplayOIDFile(rootfile);
740 daniel-mar 1029
end;
1030
 
733 daniel-mar 1031
procedure OP_ReturnToMSDOS;
1032
begin
747 daniel-mar 1033
  (* Note: These two lines don't seem to be necessary if you use DoneVideo *)
1034
  ResetDefaultDosColors;
746 daniel-mar 1035
  ClrScr; (*Important, so that the DOS command prompt is also LightGray *)
1036
 
741 daniel-mar 1037
  WriteLn('Thank you for using OIDplus for DOS.');
743 daniel-mar 1038
  WriteLn('');
733 daniel-mar 1039
end;
1040
 
741 daniel-mar 1041
function _GetTreeViewLine(oid: POID; indent: integer): string;
740 daniel-mar 1042
var
1043
  i: integer;
747 daniel-mar 1044
  sTmp, sTmp2: string;
740 daniel-mar 1045
begin
1046
  (* Build line *)
1047
  sTmp := RepeatStr(' ', indent*TREEVIEW_INDENT);
1048
  if oid^.DotNotation = '' then
1049
    sTmp := sTmp + 'Object Identifiers'
1050
  else
1051
    sTmp := sTmp + oid^.DotNotation;
1052
  sTmp := sTmp + _ShowAsnIds(oid);
1053
  if TREEVIEW_INCLUDE_DESC then
1054
  begin
1055
    if Trim(oid^.Description) <> '' then
1056
    begin
1057
      sTmp := sTmp + ': ' + oid^.Description;
1058
    end;
1059
  end;
747 daniel-mar 1060
 
1061
  sTmp := StringReplace(sTmp, #13#10, ' ');
1062
  repeat
1063
    sTmp2 := sTmp;
1064
    sTmp := StringReplace(sTmp, '  ', ' ');
1065
  until sTmp = sTmp2;
1066
 
744 daniel-mar 1067
  sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
741 daniel-mar 1068
  _GetTreeViewLine := sTmp;
740 daniel-mar 1069
end;
1070
 
1071
procedure _RecTreeExport(oid: POID; var F: Text; indent: integer);
1072
var
1073
  i: integer;
1074
  sTmp: string;
1075
  suboid: POID;
1076
  childFilename: string;
1077
begin
741 daniel-mar 1078
  sTmp := _GetTreeViewLine(oid, indent);
740 daniel-mar 1079
  sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1080
  WriteLn(F, sTmp);
1081
 
1082
  (* Recursively call children *)
1083
  for i := 0 to ListCount(oid^.SubIds)-1 do
1084
  begin
1085
    sTmp := ListGetElement(oid^.SubIds, i);
1086
    CreateOidDef(suboid);
744 daniel-mar 1087
    childFilename := FileIdPart(sTmp) + OID_EXTENSION;
743 daniel-mar 1088
    if not FileExists(childFilename) then
740 daniel-mar 1089
    begin
744 daniel-mar 1090
      sTmp := 'ERROR: MISSING ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
743 daniel-mar 1091
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1092
      WriteLn(F, sTmp);
740 daniel-mar 1093
    end
743 daniel-mar 1094
    else if not _ReadOidFile(childFilename, suboid, false) then
740 daniel-mar 1095
    begin
744 daniel-mar 1096
      sTmp := 'ERROR: READ ERROR AT ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
740 daniel-mar 1097
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1098
      WriteLn(F, sTmp);
743 daniel-mar 1099
    end
745 daniel-mar 1100
    else if (suboid^.ParentFileId <> oid^.FileId) or
1101
            (suboid^.ParentDotNotation <> oid^.DotNotation) then
744 daniel-mar 1102
    begin
1103
      (* This can happen if a file is missing, and then another OID gets this filename since the number seems to be free *)
1104
      sTmp := 'ERROR: BAD BACKREF AT ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1105
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1106
      WriteLn(F, sTmp);
1107
    end
743 daniel-mar 1108
    else
1109
    begin
1110
      _RecTreeExport(suboid, F, indent+1);
1111
      FreeOidDef(suboid);
1112
    end
740 daniel-mar 1113
  end;
1114
end;
1115
 
747 daniel-mar 1116
procedure TreeViewPreview;
1117
var
1118
  list: PStringList;
1119
begin
748 daniel-mar 1120
  ClrScr;
1121
  DrawTitleBar('TreeView Export', TITLEBAR_LEFT_TEXT, TREEVIEW_FILENAME);
1122
  DrawStatusBar('Press ESC to return to the main menu');
1123
 
747 daniel-mar 1124
  CreateList(list);
1125
 
1126
  ListLoadFromFile(list, TREEVIEW_FILENAME);
1127
  DrawSelectionList(2, 3, ScreenWidth-2, ScreenHeight-4,
1128
                    list, true, 'PREVIEW OF '+TREEVIEW_FILENAME, 2);
1129
  (* TODO: Jump to selected OID *)
1130
 
1131
  DrawStatusBar(DEFAULT_STATUSBAR);
1132
 
1133
  FreeList(list);
1134
end;
1135
 
740 daniel-mar 1136
procedure OP_TreeView;
1137
var
1138
  F: Text;
1139
  rootoid: POID;
742 daniel-mar 1140
  rootfile: string;
743 daniel-mar 1141
  res: boolean;
740 daniel-mar 1142
begin
1143
  ClrScr;
1144
  DrawTitleBar('TreeView Export', TITLEBAR_LEFT_TEXT, '');
1145
  DrawStatusBar('Exporting data... please wait...');
1146
 
742 daniel-mar 1147
  (* This will try creating a new root file if it does not exist *)
743 daniel-mar 1148
  rootfile := _GetRootFile(true);
1149
  if rootfile = '' then
1150
  begin
1151
    DrawStatusBar(DEFAULT_STATUSBAR);
1152
    Exit;
1153
  end;
742 daniel-mar 1154
 
744 daniel-mar 1155
  Assign(F, TREEVIEW_FILENAME);
743 daniel-mar 1156
  {$I-}
740 daniel-mar 1157
  Rewrite(F);
743 daniel-mar 1158
  {$I+}
1159
  if IoResult <> 0 then
1160
  begin
1161
    (* Can happen if disk is read-only (Runtime Error 150) *)
744 daniel-mar 1162
    ShowMessage('Cannot open '+TREEVIEW_FILENAME+' for writing.', 'ERROR', true);
743 daniel-mar 1163
    _Pause;
1164
    DrawStatusBar(DEFAULT_STATUSBAR);
1165
    Exit;
1166
  end;
740 daniel-mar 1167
 
743 daniel-mar 1168
  res := false;
740 daniel-mar 1169
  CreateOidDef(rootoid);
743 daniel-mar 1170
  if _ReadOidFile(rootfile, rootoid, true) then
1171
  begin
1172
    _RecTreeExport(rootoid, F, 0);
1173
    res := true;
1174
  end;
740 daniel-mar 1175
  FreeOidDef(rootoid);
1176
 
743 daniel-mar 1177
  Close(F);
1178
 
740 daniel-mar 1179
  DrawStatusBar(DEFAULT_STATUSBAR);
743 daniel-mar 1180
  if res then
1181
  begin
744 daniel-mar 1182
    ShowMessage('TreeView successfully exported as '+TREEVIEW_FILENAME, 'TREEVIEW EXPORT', true);
743 daniel-mar 1183
    _Pause;
1184
  end;
747 daniel-mar 1185
 
1186
  TreeViewPreview;
740 daniel-mar 1187
end;
1188
 
733 daniel-mar 1189
procedure OP_MainMenu;
1190
var
1191
  menu: PStringList;
1192
  menuRes, menuLeft, menuTop: integer;
747 daniel-mar 1193
  menuIdOID, menuIdTree, menuIdExit: integer;
733 daniel-mar 1194
begin
1195
  repeat
1196
    ClrScr;
1197
 
738 daniel-mar 1198
    DrawTitleBar('Welcome to OIDplus for DOS', '', '');
733 daniel-mar 1199
    DrawStatusBar(DEFAULT_STATUSBAR);
1200
    GoToXY(ScreenWidth-Length(VERSIONINFO), ScreenHeight-1);
1201
    Write(VERSIONINFO);
1202
 
735 daniel-mar 1203
    CreateList(menu);
1204
 
1205
    menuIdOID  := ListAppend(menu, 'Manage OIDs');
740 daniel-mar 1206
    menuIdTree := ListAppend(menu, 'Export TreeView');
735 daniel-mar 1207
    menuIdExit := ListAppend(menu, 'Return to DOS');
1208
 
1209
    menuLeft := round(ScreenWidth/2 -MAINMENU_WIDTH/2);
1210
    menuTop  := round(ScreenHeight/2-MAINMENU_HEIGHT/2);
1211
    menuRes  := DrawSelectionList(menuLeft, menuTop,
1212
                                  MAINMENU_WIDTH, MAINMENU_HEIGHT,
1213
                                  menu, true, 'MAIN MENU', 2);
733 daniel-mar 1214
    FreeList(menu);
1215
 
735 daniel-mar 1216
    if menuRes = menuIdOID then
733 daniel-mar 1217
    begin
1218
      OP_ManageOIDs;
735 daniel-mar 1219
    end
740 daniel-mar 1220
    else if menuRes = menuIdTree then
1221
    begin
1222
      OP_Treeview;
733 daniel-mar 1223
    end;
735 daniel-mar 1224
  until (menuRes = menuIdExit) or (MAINMENU_ALLOW_ESC and (menuRes = -1));
733 daniel-mar 1225
 
1226
  OP_ReturnToMSDOS;
1227
end;
1228
 
1229
begin
746 daniel-mar 1230
  InitVideo; (* sets ScreenWidth and ScreenHeight *)
1231
  CursorOff;
733 daniel-mar 1232
  OP_MainMenu;
747 daniel-mar 1233
  CursorOn;
746 daniel-mar 1234
  DoneVideo;
733 daniel-mar 1235
end.