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

Subversion Repositories eco32

[/] [eco32/] [trunk/] [binutils/] [ar/] [ar.c] - Blame information for rev 253

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 7 hellwig
/*
2
 * ar.c -- archiver
3
 */
4
 
5
 
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <string.h>
9
#include <signal.h>
10
#include <unistd.h>
11
#include <sys/stat.h>
12
#include <fcntl.h>
13
#include <time.h>
14
 
15
#include "endian.h"
16
#include "ranlib.h"
17
#include "../include/ar.h"
18
 
19
 
20
/**************************************************************/
21
 
22
 
23
#define BUFSIZE 512
24
 
25
#define SKIP    0x01
26
#define IODD    0x02
27
#define OODD    0x04
28
#define HEAD    0x08
29
 
30
 
31
char *com = "drqtpmx";
32
char *opt = "vuabcls";
33
 
34
int signums[] = { SIGHUP, SIGINT, SIGQUIT, 0 };
35
 
36
void (*comfun)(void);
37
int flg[26];
38
 
39
char *arnam;
40
int af;
41
 
42
char **namv;
43
int namc;
44
 
45
int baState;
46
char *posName;
47
 
48
char tmp0nam[20];
49
char tmp1nam[20];
50
char tmp2nam[20];
51
char *tf0nam;
52
char *tf1nam;
53
char *tf2nam;
54
int tf0;
55
int tf1;
56
int tf2;
57
int qf;
58
 
59
char *file;
60
char name[MAX_NAME];
61
 
62
struct stat stbuf;
63
ArHeader arbuf;
64
unsigned char buf[BUFSIZE];
65
 
66
 
67
/**************************************************************/
68
 
69
 
70
#define IFMT    070000
71
#define SUID    004000
72
#define SGID    002000
73
#define STXT    001000
74
#define ROWN    000400
75
#define WOWN    000200
76
#define XOWN    000100
77
#define RGRP    000040
78
#define WGRP    000020
79
#define XGRP    000010
80
#define ROTH    000004
81
#define WOTH    000002
82
#define XOTH    000001
83
 
84
 
85
int m1[] = { 1, ROWN, 'r', '-' };
86
int m2[] = { 1, WOWN, 'w', '-' };
87
int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };
88
int m4[] = { 1, RGRP, 'r', '-' };
89
int m5[] = { 1, WGRP, 'w', '-' };
90
int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };
91
int m7[] = { 1, ROTH, 'r', '-' };
92
int m8[] = { 1, WOTH, 'w', '-' };
93
int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };
94
 
95
int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9 };
96
 
97
 
98
void selectChar(int *pairp) {
99
  int *ap;
100
  int n;
101
 
102
  ap = pairp;
103
  n = *ap++;
104
  while (--n >= 0 && (arbuf.mode & *ap++) == 0) {
105
    ap++;
106
  }
107
  putchar(*ap);
108
}
109
 
110
 
111
void printMode(void) {
112
  int **mp;
113
 
114
  for (mp = &m[0]; mp < &m[9]; mp++) {
115
    selectChar(*mp);
116
  }
117
}
118
 
119
 
120
void showAttributes(void) {
121
  char *cp;
122
 
123
  printMode();
124
  printf("%4d/%4d", arbuf.uid, arbuf.gid);
125 253 hellwig
  printf("%8d", arbuf.size);
126 7 hellwig
  cp = ctime(&arbuf.date);
127
  printf(" %-12.12s %-4.4s ", cp + 4, cp + 20);
128
}
129
 
130
 
131
/**************************************************************/
132
 
133
 
134
void mesg(int c) {
135
  if (flg['v' - 'a']) {
136
    printf("%c - %s\n", c, file);
137
  }
138
}
139
 
140
 
141
char *trim(char *s) {
142
  char *p1;
143
  char *p2;
144
 
145
  for (p1 = s; *p1 != '\0'; p1++) ;
146
  while (p1 > s) {
147
    if (*--p1 != '/') {
148
      break;
149
    }
150
    *p1 = '\0';
151
  }
152
  p2 = s;
153
  for (p1 = s; *p1 != '\0'; p1++) {
154
    if (*p1 == '/') {
155
      p2 = p1 + 1;
156
    }
157
  }
158
  return p2;
159
}
160
 
161
 
162
int notFound(void) {
163
  int n;
164
  int i;
165
 
166
  n = 0;
167
  for (i = 0; i < namc; i++) {
168
    if (namv[i] != NULL) {
169
      fprintf(stderr, "ar: %s not found\n", namv[i]);
170
      n++;
171
    }
172
  }
173
  return n;
174
}
175
 
176
 
177
int moreFiles(void) {
178
  int n;
179
  int i;
180
 
181
  n = 0;
182
  for (i = 0; i < namc; i++) {
183
    if (namv[i] != NULL) {
184
      n++;
185
    }
186
  }
187
  return n;
188
}
189
 
190
 
191
void unlinkTempFiles(void) {
192
  if (tf0nam != NULL) {
193
    unlink(tf0nam);
194
  }
195
  if (tf1nam != NULL) {
196
    unlink(tf1nam);
197
  }
198
  if (tf2nam != NULL) {
199
    unlink(tf2nam);
200
  }
201
}
202
 
203
 
204
void done(int c) {
205
  unlinkTempFiles();
206
  exit(c);
207
}
208
 
209
 
210
void sigDone(int signum) {
211
  done(100);
212
}
213
 
214
 
215
void noArchive(void) {
216
  fprintf(stderr, "ar: %s does not exist\n", arnam);
217
  done(1);
218
}
219
 
220
 
221
void writeError(void) {
222
  perror("ar write error");
223
  done(1);
224
}
225
 
226
 
227
void phaseError(void) {
228
  fprintf(stderr, "ar: phase error on %s\n", file);
229
}
230
 
231
 
232
int stats(void) {
233
  int f;
234
 
235
  f = open(file, O_RDONLY);
236
  if (f < 0) {
237
    return f;
238
  }
239
  if (fstat(f, &stbuf) < 0) {
240
    close(f);
241
    return -1;
242
  }
243
  return f;
244
}
245
 
246
 
247
int match(void) {
248
  int i;
249
 
250
  for (i = 0; i < namc; i++) {
251
    if (namv[i] == NULL) {
252
      continue;
253
    }
254
    if (strcmp(trim(namv[i]), file) == 0) {
255
      file = namv[i];
256
      namv[i] = NULL;
257
      return 1;
258
    }
259
  }
260
  return 0;
261
}
262
 
263
 
264
void baMatch(void) {
265
  int f;
266
 
267
  if (baState == 1) {
268
    if (strcmp(file, posName) != 0) {
269
      return;
270
    }
271
    baState = 2;
272
    if (flg['a' - 'a']) {
273
      return;
274
    }
275
  }
276
  if (baState == 2) {
277
    baState = 0;
278
    tf1nam = mktemp(tmp1nam);
279
    close(creat(tf1nam, 0600));
280
    f = open(tf1nam, O_RDWR);
281
    if (f < 0) {
282
      fprintf(stderr, "ar: cannot create second temp file\n");
283
      return;
284
    }
285
    tf1 = tf0;
286
    tf0 = f;
287
  }
288
}
289
 
290
 
291
/**************************************************************/
292
 
293
 
294
void init(void) {
295
  unsigned int mbuf;
296
 
297
  write4ToEco((unsigned char *) &mbuf, AR_MAGIC);
298
  tf0nam = mktemp(tmp0nam);
299
  close(creat(tf0nam, 0600));
300
  tf0 = open(tf0nam, O_RDWR);
301
  if (tf0 < 0) {
302
    fprintf(stderr, "ar: cannot create temp file\n");
303
    done(1);
304
  }
305
  if (write(tf0, &mbuf, sizeof(mbuf)) != sizeof(mbuf)) {
306
    writeError();
307
  }
308
}
309
 
310
 
311
int getArchive(void) {
312
  unsigned int mbuf;
313
 
314
  af = open(arnam, O_RDONLY);
315
  if (af < 0) {
316
    return 1;
317
  }
318
  if (read(af, &mbuf, sizeof(mbuf)) != sizeof(mbuf) ||
319
      read4FromEco((unsigned char *) &mbuf) != AR_MAGIC) {
320
    fprintf(stderr, "ar: %s not in archive format\n", arnam);
321
    done(1);
322
  }
323
  return 0;
324
}
325
 
326
 
327
void getQuick(void) {
328
  unsigned int mbuf;
329
 
330
  qf = open(arnam, O_RDWR);
331
  if (qf < 0) {
332
    if (!flg['c' - 'a']) {
333
      fprintf(stderr, "ar: creating %s\n", arnam);
334
    }
335
    close(creat(arnam, 0666));
336
    qf = open(arnam, O_RDWR);
337
    if (qf < 0) {
338
      fprintf(stderr, "ar: cannot create %s\n", arnam);
339
      done(1);
340
    }
341
    write4ToEco((unsigned char *) &mbuf, AR_MAGIC);
342
    if (write(qf, &mbuf, sizeof(mbuf)) != sizeof(mbuf)) {
343
      writeError();
344
    }
345
  } else
346
  if (read(qf, &mbuf, sizeof(mbuf)) != sizeof(mbuf) ||
347
      read4FromEco((unsigned char *) &mbuf) != AR_MAGIC) {
348
    fprintf(stderr, "ar: %s not in archive format\n", arnam);
349
    done(1);
350
  }
351
}
352
 
353
 
354
int getMember(void) {
355
  int i;
356
 
357
  i = read(af, &arbuf, sizeof(arbuf));
358
  if (i != sizeof(arbuf)) {
359
    if (tf1nam != NULL) {
360
      i = tf0;
361
      tf0 = tf1;
362
      tf1 = i;
363
    }
364
    return 1;
365
  }
366
  conv4FromEcoToNative((unsigned char *) &arbuf.date);
367
  conv4FromEcoToNative((unsigned char *) &arbuf.uid);
368
  conv4FromEcoToNative((unsigned char *) &arbuf.gid);
369
  conv4FromEcoToNative((unsigned char *) &arbuf.mode);
370
  conv4FromEcoToNative((unsigned char *) &arbuf.size);
371
  for (i = 0; i < MAX_NAME; i++) {
372
    name[i] = arbuf.name[i];
373
  }
374
  file = name;
375
  return 0;
376
}
377
 
378
 
379
void copyFile(int fi, int fo, int flags) {
380
  int pe;
381
  int icount, ocount;
382
  int pad;
383
 
384
  if (flags & HEAD) {
385
    conv4FromNativeToEco((unsigned char *) &arbuf.date);
386
    conv4FromNativeToEco((unsigned char *) &arbuf.uid);
387
    conv4FromNativeToEco((unsigned char *) &arbuf.gid);
388
    conv4FromNativeToEco((unsigned char *) &arbuf.mode);
389
    conv4FromNativeToEco((unsigned char *) &arbuf.size);
390
    if (write(fo, &arbuf, sizeof(arbuf)) != sizeof(arbuf)) {
391
      writeError();
392
    }
393
    conv4FromEcoToNative((unsigned char *) &arbuf.date);
394
    conv4FromEcoToNative((unsigned char *) &arbuf.uid);
395
    conv4FromEcoToNative((unsigned char *) &arbuf.gid);
396
    conv4FromEcoToNative((unsigned char *) &arbuf.mode);
397
    conv4FromEcoToNative((unsigned char *) &arbuf.size);
398
  }
399
  pe = 0;
400
  while (arbuf.size > 0) {
401
    icount = ocount = BUFSIZE;
402
    if (arbuf.size < icount) {
403
      icount = ocount = arbuf.size;
404
      pad = -icount & 0x03;
405
      if (flags & IODD) {
406
        icount += pad;
407
      }
408
      if (flags & OODD) {
409
        ocount += pad;
410
      }
411
    }
412
    if (read(fi, buf, icount) != icount) {
413
      pe++;
414
    }
415
    if ((flags & SKIP) == 0) {
416
      if (write(fo, buf, ocount) != ocount) {
417
        writeError();
418
      }
419
    }
420
    arbuf.size -= BUFSIZE;
421
  }
422
  if (pe != 0) {
423
    phaseError();
424
  }
425
}
426
 
427
 
428
void moveFile(int f) {
429
  char *cp;
430
  int i;
431
 
432
  cp = trim(file);
433
  for (i = 0; i < MAX_NAME; i++) {
434
    if ((arbuf.name[i] = *cp) != '\0') {
435
      cp++;
436
    }
437
  }
438
  arbuf.size = stbuf.st_size;
439
  arbuf.date = stbuf.st_mtime;
440
  arbuf.uid = stbuf.st_uid;
441
  arbuf.gid = stbuf.st_gid;
442
  arbuf.mode = stbuf.st_mode;
443
  copyFile(f, tf0, OODD | HEAD);
444
  close(f);
445
}
446
 
447
 
448
void install(void) {
449
  int i;
450
 
451
  for (i = 0; signums[i] != 0; i++) {
452
    signal(signums[i], SIG_IGN);
453
  }
454
  if (af < 0) {
455
    if (!flg['c' - 'a']) {
456
      fprintf(stderr, "ar: creating %s\n", arnam);
457
    }
458
  }
459
  close(af);
460
  af = creat(arnam, 0666);
461
  if (af < 0) {
462
    fprintf(stderr, "ar: cannot create %s\n", arnam);
463
    done(1);
464
  }
465
  if (tf0nam != NULL) {
466
    lseek(tf0, 0, SEEK_SET);
467
    while ((i = read(tf0, buf, BUFSIZE)) > 0) {
468
      if (write(af, buf, i) != i) {
469
        writeError();
470
      }
471
    }
472
  }
473
  if (tf2nam != NULL) {
474
    lseek(tf2, 0, SEEK_SET);
475
    while ((i = read(tf2, buf, BUFSIZE)) > 0) {
476
      if (write(af, buf, i) != i) {
477
        writeError();
478
      }
479
    }
480
  }
481
  if (tf1nam != NULL) {
482
    lseek(tf1, 0, SEEK_SET);
483
    while ((i = read(tf1, buf, BUFSIZE)) > 0) {
484
      if (write(af, buf, i) != i) {
485
        writeError();
486
      }
487
    }
488
  }
489
}
490
 
491
 
492
void cleanup(void) {
493
  int i;
494
  int f;
495
 
496
  for (i = 0; i < namc; i++) {
497
    file = namv[i];
498
    if (file == NULL) {
499
      continue;
500
    }
501
    namv[i] = NULL;
502
    mesg('a');
503
    f = stats();
504
    if (f < 0) {
505
      fprintf(stderr, "ar: cannot open %s\n", file);
506
      continue;
507
    }
508
    moveFile(f);
509
  }
510
}
511
 
512
 
513
/**************************************************************/
514
 
515
 
516
void dCmd(void) {
517
  init();
518
  if (getArchive()) {
519
    noArchive();
520
  }
521
  while (!getMember()) {
522
    if (match()) {
523
      mesg('d');
524
      copyFile(af, -1, IODD | SKIP);
525
      continue;
526
    }
527
    mesg('c');
528
    copyFile(af, tf0, IODD | OODD | HEAD);
529
  }
530
  install();
531
}
532
 
533
 
534
void rCmd(void) {
535
  int f;
536
 
537
  init();
538
  getArchive();
539
  while (!getMember()) {
540
    baMatch();
541
    if (namc == 0 || match()) {
542
      f = stats();
543
      if (f < 0) {
544
        if (namc != 0) {
545
          fprintf(stderr, "ar: cannot open %s\n", file);
546
        }
547
        goto cp;
548
      }
549
      if (flg['u' - 'a']) {
550
        if (stbuf.st_mtime <= arbuf.date) {
551
          close(f);
552
          goto cp;
553
        }
554
      }
555
      mesg('r');
556
      copyFile(af, -1, IODD | SKIP);
557
      moveFile(f);
558
      continue;
559
    }
560
cp:
561
    mesg('c');
562
    copyFile(af, tf0, IODD | OODD | HEAD);
563
  }
564
  cleanup();
565
  install();
566
}
567
 
568
 
569
void qCmd(void) {
570
  int i;
571
  int f;
572
 
573
  if (flg['a' - 'a'] || flg['b' - 'a']) {
574
    fprintf(stderr, "ar: [ab] not allowed with -q\n");
575
    done(1);
576
  }
577
  getQuick();
578
  for (i = 0; signums[i] != 0; i++) {
579
    signal(signums[i], SIG_IGN);
580
  }
581
  lseek(qf, 0, SEEK_END);
582
  for (i = 0; i < namc; i++) {
583
    file = namv[i];
584
    if (file == NULL) {
585
      continue;
586
    }
587
    namv[i] = NULL;
588
    mesg('q');
589
    f = stats();
590
    if (f < 0) {
591
      fprintf(stderr, "ar: cannot open %s\n", file);
592
      continue;
593
    }
594
    tf0 = qf;
595
    moveFile(f);
596
    qf = tf0;
597
  }
598
}
599
 
600
 
601
void tCmd(void) {
602
  if (getArchive()) {
603
    noArchive();
604
  }
605
  while (!getMember()) {
606
    if (namc == 0 || match()) {
607
      if (flg['v' - 'a']) {
608
        showAttributes();
609
      }
610
      printf("%s\n", trim(file));
611
    }
612
    copyFile(af, -1, IODD | SKIP);
613
  }
614
}
615
 
616
 
617
void pCmd(void) {
618
  if (getArchive()) {
619
    noArchive();
620
  }
621
  while (!getMember()) {
622
    if (namc == 0 || match()) {
623
      if (flg['v' - 'a']) {
624
        printf("\n<%s>\n\n", file);
625
        fflush(stdout);
626
      }
627
      copyFile(af, 1, IODD);
628
      continue;
629
    }
630
    copyFile(af, -1, IODD | SKIP);
631
  }
632
}
633
 
634
 
635
void mCmd(void) {
636
  init();
637
  if (getArchive()) {
638
    noArchive();
639
  }
640
  tf2nam = mktemp(tmp2nam);
641
  close(creat(tf2nam, 0600));
642
  tf2 = open(tf2nam, O_RDWR);
643
  if (tf2 < 0) {
644
    fprintf(stderr, "ar: cannot create third temp file\n");
645
    done(1);
646
  }
647
  while (!getMember()) {
648
    baMatch();
649
    if (match()) {
650
      mesg('m');
651
      copyFile(af, tf2, IODD | OODD | HEAD);
652
      continue;
653
    }
654
    mesg('c');
655
    copyFile(af, tf0, IODD | OODD | HEAD);
656
  }
657
  install();
658
}
659
 
660
 
661
void xCmd(void) {
662
  int f;
663
 
664
  if (getArchive()) {
665
    noArchive();
666
  }
667
  while (!getMember()) {
668
    if (namc == 0 || match()) {
669
      f = creat(file, arbuf.mode & 0777);
670
      if (f < 0) {
671
        fprintf(stderr, "ar: cannot create %s\n", file);
672
        goto sk;
673
      }
674
      mesg('x');
675
      copyFile(af, f, IODD);
676
      close(f);
677
      continue;
678
    }
679
sk:
680
    mesg('c');
681
    copyFile(af, -1, IODD | SKIP);
682
    if (namc > 0 && !moreFiles()) {
683
      done(0);
684
    }
685
  }
686
}
687
 
688
 
689
/**************************************************************/
690
 
691
/* specialized r command for updating symbols */
692
 
693
 
694
int exec_rCmd(int create, char *args[]) {
695
  int i;
696
  int res;
697
 
698
  /* reset all global variables */
699
  comfun = NULL;
700
  for (i = 0; i < 26; i++) {
701
    flg[i] = 0;
702
  }
703
  arnam = NULL;
704
  af = 0;
705
  namv = NULL;
706
  namc = 0;
707
  baState = 0;
708
  posName = NULL;
709
  for (i = 0; i < 20; i++) {
710
    tmp0nam[i] = '\0';
711
    tmp1nam[i] = '\0';
712
    tmp2nam[i] = '\0';
713
  }
714
  tf0nam = NULL;
715
  tf1nam = NULL;
716
  tf2nam = NULL;
717
  tf0 = 0;
718
  tf1 = 0;
719
  tf2 = 0;
720
  qf = 0;
721
  file = NULL;
722
  for (i = 0; i < MAX_NAME; i++) {
723
    name[i] = '\0';
724
  }
725
  /* prepare arguments, call r command, cleanup */
726
  comfun = rCmd;
727
  flg['l' - 'a'] = 1;
728
  strcpy(tmp0nam, "v0XXXXXX");
729
  strcpy(tmp1nam, "v1XXXXXX");
730
  strcpy(tmp2nam, "v2XXXXXX");
731
  if (create) {
732
    /* ar -rlb firstName archive TEMP_NAME */
733
    flg['b' - 'a'] = 1;
734
    baState = 1;
735
    posName = trim(args[0]);
736
    arnam = args[1];
737
    namv = &args[2];
738
    namc = 1;
739
  } else {
740
    /* ar -rl archive TEMP_NAME */
741
    arnam = args[0];
742
    namv = &args[1];
743
    namc = 1;
744
  }
745
  (*comfun)();
746
  res = notFound();
747
  unlinkTempFiles();
748
  return res;
749
}
750
 
751
 
752
/**************************************************************/
753
 
754
 
755
void usage(void) {
756
  printf("usage: ar -[%s][%s] archive files ...\n", com, opt);
757
  done(1);
758
}
759
 
760
 
761
void setcom(void (*fun)(void)) {
762
  if (comfun != NULL) {
763
    fprintf(stderr, "ar: only one of [%s] allowed\n", com);
764
    done(1);
765
  }
766
  comfun = fun;
767
}
768
 
769
 
770
int cmdCanChangeSymbols(void) {
771
  return comfun == dCmd ||
772
         comfun == rCmd ||
773
         comfun == mCmd;
774
}
775
 
776
 
777
int main(int argc, char *argv[]) {
778
  int i;
779
  char *cp;
780
  int res;
781
 
782
  for (i = 0; signums[i] != 0; i++) {
783
    if (signal(signums[i], SIG_IGN) != SIG_IGN) {
784
      signal(signums[i], sigDone);
785
    }
786
  }
787
  strcpy(tmp0nam, "/tmp/v0XXXXXX");
788
  strcpy(tmp1nam, "/tmp/v1XXXXXX");
789
  strcpy(tmp2nam, "/tmp/v2XXXXXX");
790
  if (argc < 3 || *argv[1] != '-') {
791
    usage();
792
  }
793
  for (cp = argv[1] + 1; *cp != '\0'; cp++) {
794
    switch (*cp) {
795
      case 'd':
796
        setcom(dCmd);
797
        break;
798
      case 'r':
799
        setcom(rCmd);
800
        break;
801
      case 'q':
802
        setcom(qCmd);
803
        break;
804
      case 't':
805
        setcom(tCmd);
806
        break;
807
      case 'p':
808
        setcom(pCmd);
809
        break;
810
      case 'm':
811
        setcom(mCmd);
812
        break;
813
      case 'x':
814
        setcom(xCmd);
815
        break;
816
      case 'v':
817
      case 'u':
818
      case 'a':
819
      case 'b':
820
      case 'c':
821
      case 'l':
822
      case 's':
823
        flg[*cp - 'a'] = 1;
824
        break;
825
      default:
826
        fprintf(stderr, "ar: bad option '%c'\n", *cp);
827
        done(1);
828
    }
829
  }
830
  if (flg['l' - 'a']) {
831
    strcpy(tmp0nam, "v0XXXXXX");
832
    strcpy(tmp1nam, "v1XXXXXX");
833
    strcpy(tmp2nam, "v2XXXXXX");
834
  }
835
  if (flg['a' - 'a'] || flg['b' - 'a']) {
836
    baState = 1;
837
    posName = trim(argv[2]);
838
    argv++;
839
    argc--;
840
    if (argc < 3) {
841
      usage();
842
    }
843
  }
844
  arnam = argv[2];
845
  namv = argv + 3;
846
  namc = argc - 3;
847
  if (comfun == NULL && !flg['s' - 'a']) {
848
    fprintf(stderr, "ar: one of [%ss] must be specified\n", com);
849
    done(1);
850
  }
851
  res = 0;
852
  if (comfun != NULL) {
853
    (*comfun)();
854
    res = notFound();
855
    unlinkTempFiles();
856
    if (res != 0) {
857
      return res;
858
    }
859
  }
860
  if (flg['s' - 'a'] ||
861
      (cmdCanChangeSymbols() && hasSymbols(arnam))) {
862
    res = updateSymbols(arnam, flg['v' - 'a']);
863
  }
864
  return res;
865
}

powered by: WebSVN 2.1.0

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