My Project
Loading...
Searching...
No Matches
feResource.cc
Go to the documentation of this file.
1/****************************************
2* Computer Algebra System SINGULAR *
3****************************************/
4/*
5* ABSTRACT: management of resources
6*/
7
8#include "singular_resourcesconfig.h"
9#include "feResource.h"
10#include "omFindExec.h"
11
12#include <stdlib.h>
13#include <unistd.h>
14#include <string.h>
15#include <stdio.h>
16#include <sys/param.h>
17
18
20
21//char* feResource(const char id, int warn = -1);
22//char* feResource(const char* key, int warn = -1);
23
24// define RESOURCE_DEBUG for chattering about resource management
25// #define RESOURCE_DEBUG
26
27#define SINGULAR_DEFAULT_DIR PREFIX
28
29/*****************************************************************
30 *
31 * Declarations: Data structures
32 *
33 *****************************************************************/
34// feSprintf transforms format strings as follows:
35// 1.) substrings of the form %c (c being a letter) are replaced by respective resource value
36// 2.) substrings of the form $string are replaced by value of resp. env variable
37
38// feCleanResource makes furthermore the following transformations (except for URL resources)
39// 1.) '/' characters are replaced by respective directory - separators
40// 2.) ';' characters are replaced by respective path separators
42{
43 {"SearchPath", 's', feResPath, NULL,
44 "$SINGULARPATH;"
45 "%D/singular/LIB;"
46 "%r/share/singular/LIB;"
47 "%b/../share/singular/LIB;"
48 // gftables:
49 "%D/factory;"
50 "%r/share/factory;"
51 "%b/LIB;"
52 "%b/../LIB;" // not installed, shared is in .libs/Singular
53 "%b/../factory;"
54 "%b/../../factory;" // not installed, shared is in .libs/Singular
55 // path for dynamic modules, should match ProcDir:
56 "%b/MOD;"
57 "%b/../MOD;" // Singular in .libs/Singular
58 "%r/lib/singular/MOD;"
59 LIB_DIR "/singular/MOD;"
60 "%b;"
61 "%b/..", // Singular in .libs/Singular
62 (char *)""},
63 {"Singular", 'S', feResBinary,"SINGULAR_EXECUTABLE", "%d/Singular", (char *)""},
64 {"BinDir", 'b', feResDir, "SINGULAR_BIN_DIR", "", (char *)""},
65 // should be changed to %b/../lib/singular/pProcs/:
66 {"ProcDir", 'P', feResPath, "SINGULAR_PROCS_DIR",
67 "%b/MOD;"
68 "%b/../MOD;" // Singular in .libs/Singular
69 "%b/..;" // Singular in .libs/Singular, programs in .
70 "%r/lib/singular/MOD;"
71 LIB_DIR "/singular/MOD;" /*debian: -> /usr/lib/singular/MOD */
72 ,(char *)""},
73 {"RootDir", 'r', feResDir, "SINGULAR_ROOT_DIR", "%b/..", (char *)""},
74 {"DataDir", 'D', feResDir, "SINGULAR_DATA_DIR", "%b/../share/", (char *)""},
75 {"DefaultDir",'d', feResDir, "SINGULAR_DEFAULT_DIR", SINGULAR_DEFAULT_DIR, (char *)""},
76 {"InfoFile", 'i', feResFile, "SINGULAR_INFO_FILE", "%D/info/singular.info.gz", (char *)""},
77 {"IdxFile", 'x', feResFile, "SINGULAR_IDX_FILE", "%D/singular/singular.idx", (char *)""},
78 {"HtmlDir", 'h', feResDir, "SINGULAR_HTML_DIR", DATA_TO_HTML_DIR, (char *)""},
79 {"ManualUrl", 'u', feResUrl, "SINGULAR_URL", "https://www.singular.uni-kl.de/Manual/", (char *)""},
80 {"ExDir", 'm', feResDir, "SINGULAR_EXAMPLES_DIR","%r/examples", (char *)""},
81 {"Path", 'p', feResPath, NULL, "%b;%P;$PATH", (char *)""},
82
83#ifdef __CYGWIN__
84 {"emacs", 'E', feResBinary,"ESINGULAR_EMACS", "%b/emacs.exe", (char *)""},
85 {"xemacs", 'A', feResBinary,"ESINGULAR_EMACS", "%b/xemacs.exe", (char *)""},
86 {"SingularEmacs",'M', feResBinary,"ESINGULAR_SINGULAR", "%b/Singular.exe", (char *)""},
87#else
88 {"emacs", 'E', feResBinary,"ESINGULAR_EMACS", "%b/emacs", (char *)""},
89 {"xemacs", 'A', feResBinary,"ESINGULAR_EMACS", "%b/xemacs", (char *)""},
90 {"SingularEmacs",'M', feResBinary,"ESINGULAR_SINGULAR", "%b/Singular", (char *)""},
91#endif
92 {"EmacsLoad", 'l', feResFile, "ESINGULAR_EMACS_LOAD", "%e/.emacs-singular", (char *)""},
93 {"EmacsDir", 'e', feResDir, "ESINGULAR_EMACS_DIR", "%D/singular/emacs", (char *)""},
94 {"SingularXterm",'M', feResBinary,"TSINGULAR_SINGULAR", "%b/Singular", (char *)""},
95#ifdef __CYGWIN__
96 {"rxvt", 'X', feResBinary,"RXVT", "%b/rxvt", (char *)""},
97#else
98 {"xterm", 'X', feResBinary,"XTERM", "%b/xterm", (char *)""},
99#endif
100 {"EmacsDir", 'e', feResDir, "SINGULAR_EMACS_DIR", "%r/emacs", (char *)""},
101 {NULL, 0, feResUndef, NULL, NULL, NULL}, // must be the last record
102};
103
104
105/*****************************************************************
106 *
107 * Declarations: Local variables / functions
108 *
109 *****************************************************************/
110
111#define MAXRESOURCELEN 5*MAXPATHLEN
112
113static feResourceConfig feGetResourceConfig(const char id);
114static feResourceConfig feGetResourceConfig(const char* key);
115static char* feResource(feResourceConfig config, int warn);
116static char* feResourceDefault(feResourceConfig config);
117static char* feInitResource(feResourceConfig config, int warn);
118static char* feGetExpandedExecutable();
119static int feVerifyResourceValue(feResourceType type, char* value);
120static char* feCleanResourceValue(feResourceType type, char* value);
121static char* feCleanUpFile(char* fname);
122static char* feCleanUpPath(char* path);
123static void mystrcpy(char* d, char* s);
124static char* feSprintf(char* s, const char* fmt, int warn = -1);
125#if defined(__CYGWIN__) && defined(__GNUC__)
126// utility function of Cygwin32:
127extern "C" int cygwin32_posix_path_list_p (const char *path);
128#endif
129
130/*****************************************************************
131 *
132 * Public functions
133 *
134 *****************************************************************/
135char* feResource(const char* key, int warn)
136{
137 return feResource(feGetResourceConfig(key), warn);
138}
139
140char* feResource(const char id, int warn)
141{
142 return feResource(feGetResourceConfig(id), warn);
143}
144
145char* feGetResource(const char id, int warn)
146{
147 return feResource(feGetResourceConfig(id), warn);
148}
149
150char* feResourceDefault(const char id)
151{
153}
154
155char* feResourceDefault(const char* key)
156{
158}
159
160void feInitResources(const char* argv0)
161{
162 if (argv0==NULL)
163 {
164 //WarnS("illegal argv[0]==NULL");
165 feArgv0 = (char*)malloc(MAXPATHLEN+strlen("/Singular"));
166 if (feArgv0 == NULL)
167 {
168 fprintf(stderr, "out of memory in initialization\n");
169 abort();
170 }
171 if (getcwd(feArgv0, MAXPATHLEN) == NULL)
172 {
173 strcpy(feArgv0, "Singular");
174 }
175 else
176 {
177 strcat(feArgv0,"/Singular");
178 }
179 }
180 else
182#ifdef RESOURCE_DEBUG
183 printf("feInitResources(argv0: '%s'): entering...\n", feArgv0);
184#endif
185 // init some Resources
186 feResource('b');
187 feResource('r');
188 // don't complain about stuff when initializing SingularPath
189 feResource('s',0);
190 feResource('P');
191}
192
194{
195 int i = 0;
196 while (feResourceConfigs[i].key != NULL)
197 {
198 if ((feResourceConfigs[i].value != NULL)
199 && (feResourceConfigs[i].value[0] != '\0'))
200 {
201 free(feResourceConfigs[i].value);
202 feResourceConfigs[i].value = (char *)"";
203 }
204 i++;
205 }
206#ifdef RESOURCE_DEBUG
207 printf("feInitResources(): entering...\n");
208#endif
209 // init some Resources
210 feResource('b');
211 feResource('r');
212 // don't complain about stuff when initializing SingularPath
213 feResource('s',0);
214}
215
216/*****************************************************************
217 *
218 * Local functions
219 *
220 *****************************************************************/
222{
223 int i = 0;
224 while (feResourceConfigs[i].key != NULL)
225 {
226 if (feResourceConfigs[i].id == id) return &(feResourceConfigs[i]);
227 i++;
228 }
229 return NULL;
230}
231
233{
234 int i = 0;
235 while (feResourceConfigs[i].key != NULL)
236 {
237 if (strcmp(feResourceConfigs[i].key, key) == 0)
238 return &(feResourceConfigs[i]);
239 i++;
240 }
241 return NULL;
242}
243
244static char* feResource(feResourceConfig config, int warn)
245{
246 if (config == NULL) return NULL;
247 if (config->value != NULL && *(config->value) != '\0') return config->value;
248 return feInitResource(config, warn);
249}
250
252{
253 if (config == NULL) return NULL;
254 char* value = (char*) malloc(MAXRESOURCELEN);
255 feSprintf(value, config->fmt, -1);
256 return value;
257}
258
259static char* feInitResource(feResourceConfig config, int warn)
260{
261 /*assume(config != NULL);*/
262#ifdef RESOURCE_DEBUG
263 printf("feInitResource(config->key: '%s', warn: '%d') : entering ...\n", config->key, warn);
264#endif
265
266 char value[MAXRESOURCELEN];
267 // now we have to work
268 // First, check Environment variable
269 if (config->env != NULL)
270 {
271 char* evalue = getenv(config->env);
272 if (evalue != NULL)
273 {
274#ifdef RESOURCE_DEBUG
275 printf("feInitResource(config,warn): Found value from env:%s\n", evalue);
276#endif
277 strcpy(value, evalue);
278 if (config->type == feResBinary // do not verify binaries
279 ||
280 feVerifyResourceValue(config->type,
281 feCleanResourceValue(config->type, value)))
282 {
283#ifdef RESOURCE_DEBUG
284 printf("feInitResource(config,warn): Set value of config (with key: '%s') to '%s'\n", config->key, value);
285#endif
286 config->value = strdup(value);
287 return config->value;
288 }
289 }
290 }
291
292 *value = '\0';
293 // Special treatment of executable
294 if (config->id == 'S')
295 {
296 char* executable = feGetExpandedExecutable();
297 if (executable != NULL)
298 {
299#ifdef RESOURCE_DEBUG
300 printf("exec:%s\n", executable);
301#endif
302 strcpy(value, executable);
303#ifdef RESOURCE_DEBUG
304 printf("value:%s\n", value);
305#endif
306 free(executable);
307 }
308 }
309 // and bindir
310 else if (config->id == 'b')
311 {
312 char* executable = feResource('S');
313#ifdef RESOURCE_DEBUG
314 printf("feInitResource(config,warn): Get '%s' from \"%s\"\n", config->key, executable);
315#endif
316 if (executable != NULL)
317 {
318 strcpy(value, executable);
319 executable = strrchr(value, DIR_SEP);
320 if (executable != NULL) *executable = '\0';
321 }
322 }
323
324#ifdef RESOURCE_DEBUG
325 printf("value:%s\n", value);
326#endif
327
328 if (*value == '\0' && config->fmt != NULL )
329 {
330 feSprintf(value, config->fmt, warn);
331 }
332 else if (config->fmt == NULL)
333 {
334 printf("Bug >>Wrong Resource Specification of '%s'<< at \"%s:%d\"\n",config->key,__FILE__,__LINE__);
335 // TODO: printf -> WarnS???
336 return NULL;
337 }
338
339 // Clean and verify
340 if (feVerifyResourceValue(config->type,
341 feCleanResourceValue(config->type, value)))
342 {
343#ifdef RESOURCE_DEBUG
344 printf("feInitResource(config,warn): Set value of '%s' to \"%s\"\n", config->key, value);
345#endif
346 config->value = strdup(value);
347 return config->value;
348 }
349 else if (config->type == feResBinary)
350 {
351 // for binaries, search through PATH once more
352 char* executable = omFindExec(config->key, value);
353 if (executable != NULL)
354 {
355 if (feVerifyResourceValue(config->type,
356 feCleanResourceValue(config->type, value)))
357 {
358 config->value = strdup(value);
359#ifdef RESOURCE_DEBUG
360 printf("feInitResource(config,warn): Set value of '%s' to \"%s\"\n", config->key, config->value);
361#endif
362 return config->value;
363 }
364 }
365 }
366
367 // issue warning if explicitely requested, or if
368 // this value is gotten for the first time
369 if (warn > 0 || (warn < 0 && config->value != NULL))
370 {
371 printf("// ** Could not get '%s'.\n", config->key);
372 printf("// ** Either set environment variable '%s' to '%s',\n",
373 config->env, config->key);
374 feSprintf(value, config->fmt, warn);
375 printf("// ** or make sure that '%s' is at \"%s\"\n", config->key, value);
376 }
377#ifdef RESOURCE_DEBUG
378 printf("feInitResource(config,warn): Set value of '%s' to NULL", config->key);
379#endif
380 config->value = NULL;
381 return NULL;
382}
383
385{
386 if (feArgv0 == NULL || *feArgv0 == '\0')
387 {
388 if (feArgv0 == NULL)
389 printf("Bug >>feArgv0 == NULL<< at %s:%d\n",__FILE__,__LINE__);
390 else
391 printf("Bug >>feArgv0 == ''<< at %s:%d\n",__FILE__,__LINE__);
392 return NULL;
393 }
394#ifdef __CYGWIN__ // stupid WINNT sometimes gives you argv[0] within ""
395 if (*feArgv0 == '"')
396 {
397 int l = strlen(feArgv0);
398 if (feArgv0[l-1] == '"')
399 {
400 feArgv0[l-1] = '\0';
401 feArgv0++;
402 }
403 }
404#endif
405#ifdef RESOURCE_DEBUG
406 printf("feGetExpandedExecutable: calling find_exec with \"%s\"\n", feArgv0);
407#endif
408 char executable[MAXRESOURCELEN];
409 char* value = omFindExec(feArgv0, executable);
410#ifdef RESOURCE_DEBUG
411 printf("feGetExpandedExecutable: find_exec exited with \"%s\": %d\n", executable, access(executable, X_OK));
412#endif
413 if (value == NULL)
414 {
415 printf("Bug >>Could not get expanded executable from \"%s\"<< at %s:%d\n",feArgv0,__FILE__,__LINE__);
416 return NULL;
417 }
418 return strdup(value);
419}
420
421
422static int feVerifyResourceValue(feResourceType type, char* value)
423{
424#ifdef RESOURCE_DEBUG
425 printf("feVerifyResourceValue(type: %d, value: \"%s\"): entering\n", (int)type, value);
426 printf("Access: ROK: %d, XOK: %d\n", access(value, R_OK), access(value, X_OK));
427#endif
428 switch(type)
429 {
430 case feResUrl:
431 case feResPath:
432 return 1;
433
434 case feResFile:
435 return ! access(value, R_OK);
436
437 case feResBinary:
438 case feResDir:
439 return ! access(value, X_OK);
440
441 default:
442 return 0;
443 }
444}
445
446/*****************************************************************
447 *
448 * Cleaning/Transformations of resource values
449 *
450 *****************************************************************/
451
452static char* feCleanResourceValue(feResourceType type, char* value)
453{
454 if (value == NULL || *value == '\0') return value;
455#ifdef RESOURCE_DEBUG
456 printf("Clean value:%s\n", value);
457#endif
458#ifdef __CYGWIN__
459#ifdef RESOURCE_DEBUG
460 printf("Clean WINNT value:%s\n", value);
461#endif
462 if (type == feResBinary)
463 {
464 int l = strlen(value);
465 if (l < 4 || (strcmp(&value[l-4], ".exe") != 0 &&
466 strcmp(&value[l-4], ".EXE") != 0))
467 strcat(value, ".exe");
468 }
469#endif
470 if (type == feResFile || type == feResBinary || type == feResDir)
471 return feCleanUpFile(value);
472 if (type == feResPath)
473 return feCleanUpPath(value);
474 return value;
475}
476
477static char* feCleanUpFile(char* fname)
478{
479 char* fn;
480
481#ifdef RESOURCE_DEBUG
482 printf("feCleanUpFile: entering with =%s=\n", fname);
483#endif
484 // Remove unnecessary .. and //
485 for (fn = fname; *fn != '\0'; fn++)
486 {
487 if (*fn == '/')
488 {
489 if (*(fn+1) == '\0')
490 {
491 if (fname != fn) *fn = '\0';
492 break;
493 }
494 if (*(fn + 1) == '/' && (fname != fn))
495 {
496 mystrcpy(fn, fn+1);
497 fn--;
498 }
499 else if (*(fn+1) == '.')
500 {
501 if (*(fn+2) == '.' && (*(fn + 3) == '/' || *(fn + 3) == '\0'))
502 {
503 #if 0
504 // this does not work: ./../../mmm will be changed to ./../mmm
505 // but we only want to change ././mmm to ./mmm
506 *fn = '\0';
507 s = strrchr(fname, '/');
508 if (s != NULL)
509 {
510 mystrcpy(s+1, fn + (*(fn + 3) != '\0' ? 4 : 3));
511 fn = s-1;
512 }
513 else
514 {
515 *fn = '/';
516 }
517 #endif
518 }
519 else if (*(fn+2) == '/' || *(fn+2) == '\0')
520 {
521 mystrcpy(fn+1, fn+3);
522 fn--;
523 }
524 }
525 }
526 }
527
528#ifdef RESOURCE_DEBUG
529 printf("feCleanUpFile: leaving with =%s=\n", fname);
530#endif
531 return fname;
532}
533
534// remove duplicates dir resp. those which do not exist
535static char* feCleanUpPath(char* path)
536{
537#ifdef RESOURCE_DEBUG
538 printf("feCleanUpPath: entering with: =%s=\n", path);
539#endif
540 if (path == NULL) return path;
541
542 int n_comps = 1, i, j;
543 char* opath = path;
544 char** path_comps;
545
546 for (; *path != '\0'; path++)
547 {
548 if (*path == fePathSep) n_comps++;
549 else if (*path == ';')
550 {
551 *path = fePathSep;
552 n_comps++;
553 }
554 }
555
556 path_comps = (char**) malloc(n_comps*sizeof(char*));
557 path_comps[0]=opath;
558 path=opath;
559 i = 1;
560
561 if (i < n_comps)
562 {
563 while (1)
564 {
565 if (*path == fePathSep)
566 {
567 *path = '\0';
568 path_comps[i] = path+1;
569 i++;
570 if (i == n_comps) break;
571 }
572 path++;
573 }
574 }
575
576 for (i=0; i<n_comps; i++)
577 path_comps[i] = feCleanUpFile(path_comps[i]);
578#ifdef RESOURCE_DEBUG
579 printf("feCleanUpPath: after CleanUpName: ");
580 for (i=0; i<n_comps; i++)
581 printf("%s:", path_comps[i]);
582 printf("\n");
583#endif
584
585 for (i=0; i<n_comps;)
586 {
587#ifdef RESOURCE_DEBUG
588 if (access(path_comps[i], X_OK | R_OK))
589 printf("feCleanUpPath: remove %d:%s -- can not access\n", i, path_comps[i]);
590#endif
591 if ( ! access(path_comps[i], X_OK | R_OK))
592 {
593 // x- permission is granted -- we assume that it is a dir
594 for (j=0; j<i; j++)
595 {
596 if (strcmp(path_comps[j], path_comps[i]) == 0)
597 {
598 // found a duplicate
599#ifdef RESOURCE_DEBUG
600 printf("feCleanUpPath: remove %d:%s -- equal to %d:%s\n", j, path_comps[j], i, path_comps[i]);
601#endif
602 j = i+1;
603 break;
604 }
605 }
606 if (j == i)
607 {
608 i++;
609 continue;
610 }
611 }
612 // now we can either not access or found a duplicate
613 path_comps[i] = NULL;
614 for (j=i+1; j<n_comps; j++)
615 path_comps[j-1] = path_comps[j];
616 n_comps--;
617 }
618
619
620 // assemble everything again
621 for (path=opath, i=0;i<n_comps-1;i++)
622 {
623 mystrcpy(path, path_comps[i]);
624 path += strlen(path);
625 *path = fePathSep;
626 path++;
627 }
628 if (n_comps)
629 {
630 mystrcpy(path, path_comps[i]);
631 }
632 else
633 {
634 *opath = '\0';
635 }
636 free(path_comps);
637#ifdef RESOURCE_DEBUG
638 printf("feCleanUpPath: leaving with path=%s=\n", opath);
639#endif
640 return opath;
641}
642
643// strcpy where source and destination may overlap
644static void mystrcpy(char* d, char* s)
645{
646 /*assume(d != NULL && s != NULL);*/
647 while (*s != '\0')
648 {
649 *d = *s;
650 d++;
651 s++;
652 }
653 *d = '\0';
654}
655
656/*****************************************************************
657 *
658 * feSprintf
659 *
660 *****************************************************************/
661static char* feSprintf(char* s, const char* fmt, int warn)
662{
663 char* s_in = s;
664 if (fmt == NULL) return NULL;
665
666 while (*fmt != '\0')
667 {
668 *s = *fmt;
669
670 if (*fmt == '%' && *(fmt + 1) != '\0')
671 {
672 fmt++;
673 char* r = feResource(*fmt, warn);
674 if (r != NULL)
675 {
676 strcpy(s, r);
677 s += strlen(r) - 1;
678 }
679 else
680 {
681 s++;
682 *s = *fmt;
683 }
684 }
685 else if (*fmt == '$' && *(fmt + 1) != '\0')
686 {
687 fmt++;
688 char* v = s + 1;
689 while (*fmt == '_' ||
690 (*fmt >= 'A' && *fmt <= 'Z') ||
691 (*fmt >= 'a' && *fmt <= 'z'))
692 {
693 *v = *fmt;
694 v++;
695 fmt++;
696 }
697 fmt--;
698 *v = '\0';
699 v = getenv(s + 1);
700 if (v != NULL) strcpy(s, v);
701 s += strlen(s) - 1;
702 }
703 s++;
704 fmt++;
705 }
706 *s = '\0';
707 return s_in;
708}
709
int l
Definition cfEzgcd.cc:100
int i
Definition cfEzgcd.cc:132
char * argv0
const CanonicalForm int s
Definition facAbsFact.cc:51
const Variable & v
< [in] a sqrfree bivariate poly
Definition facBivar.h:39
int j
Definition facHensel.cc:110
static char * feCleanUpFile(char *fname)
static feResourceConfig feGetResourceConfig(const char id)
static char * feResourceDefault(feResourceConfig config)
void feReInitResources()
VAR char * feArgv0
Definition feResource.cc:19
static char * feSprintf(char *s, const char *fmt, int warn=-1)
VAR feResourceConfig_s feResourceConfigs[]
Definition feResource.cc:41
static char * feInitResource(feResourceConfig config, int warn)
static char * feCleanUpPath(char *path)
static char * feResource(feResourceConfig config, int warn)
void feInitResources(const char *argv0)
static char * feGetExpandedExecutable()
static char * feCleanResourceValue(feResourceType type, char *value)
static int feVerifyResourceValue(feResourceType type, char *value)
char * feGetResource(const char id, int warn)
#define MAXRESOURCELEN
#define SINGULAR_DEFAULT_DIR
Definition feResource.cc:27
static void mystrcpy(char *d, char *s)
const char fePathSep
Definition feResource.h:58
#define DIR_SEP
Definition feResource.h:6
feResourceConfig_s * feResourceConfig
Definition feResource.h:31
feResourceType
Definition feResource.h:20
@ feResBinary
Definition feResource.h:20
@ feResPath
Definition feResource.h:20
@ feResDir
Definition feResource.h:20
@ feResUrl
Definition feResource.h:20
@ feResUndef
Definition feResource.h:20
@ feResFile
Definition feResource.h:20
char * getenv()
#define VAR
Definition globaldefs.h:5
#define free
Definition omAllocFunc.c:14
#define strdup
Definition omAllocFunc.c:18
#define malloc
Definition omAllocFunc.c:12
char * omFindExec(const char *name, char *exec)
Definition omFindExec.c:318
#define NULL
Definition omList.c:12
#define MAXPATHLEN
Definition omRet2Info.c:22