sfunctions.c 42 KB
Newer Older
kollo's avatar
kollo committed
1 2 3 4 5 6 7 8
/* sfunctions.c   String functions (c) Markus Hoffmann*/

/* This file is part of X11BASIC, the basic interpreter for Unix/X
 * ============================================================
 * X11BASIC is free software and comes with NO WARRANTY - read the file
 * COPYING for details
 */

kollo's avatar
kollo committed
9
#define _GNU_SOURCE
kollo's avatar
kollo committed
10 11
#include <stdio.h>
#include <stdlib.h>
12
#include <stdint.h>
kollo's avatar
kollo committed
13 14 15 16 17
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
kollo's avatar
kollo committed
18
#include <ctype.h>
kollo's avatar
kollo committed
19 20 21
#if defined(__CYGWIN__) || defined(__MINGW32__)
#include <windows.h>
#endif
kollo's avatar
kollo committed
22 23

#include "defs.h"
kollo's avatar
kollo committed
24 25 26 27 28
#ifdef HAVE_GCRYPT
  #include <gcrypt.h>
  #define GCRYPT_VERSION "1.5.0"

#endif
kollo's avatar
kollo committed
29 30
#include "x11basic.h"
#include "variablen.h"
kollo's avatar
kollo committed
31
#include "xbasic.h"
kollo's avatar
kollo committed
32
#include "type.h"
kollo's avatar
kollo committed
33
#include "functions.h"
kollo's avatar
kollo committed
34
#include "sfunctions.h"
kollo's avatar
kollo committed
35
#include "parser.h"
kollo's avatar
kollo committed
36 37
#include "parameter.h"
#include "array.h"
kollo's avatar
kollo committed
38 39
#include "io.h"
#include "wort_sep.h"
kollo's avatar
kollo committed
40

kollo's avatar
kollo committed
41
#include "decode.h"
kollo's avatar
kollo committed
42 43


kollo's avatar
kollo committed
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
#ifdef DUMMY_LIST
#define f_nop NULL
#define array_to_string NULL
#define f_fsfirsts NULL
#define f_fsnexts NULL
#define f_inputs NULL
#define f_lineinputs NULL
#define f_xtrims NULL
#define f_words  NULL
#define f_usings NULL
#define f_unixtimes NULL
#define f_unixdates NULL
#define f_uncompresss NULL
#define f_uppers NULL
#define f_lowers NULL
#define f_chrs NULL
#define f_trims NULL
#define f_terminalnames NULL
#define f_systems NULL
#define f_prgs NULL
#define f_replaces NULL
#define f_reverses NULL
#define f_mids NULL
#define f_rights NULL
#define f_lefts NULL
#define f_strings NULL
#define f_strs NULL
#define f_signs NULL
#define f_spaces NULL
#define f_rles NULL
#define f_rlds NULL
kollo's avatar
kollo committed
75 76
#define f_pngdecodes NULL
#define f_pngencodes NULL
kollo's avatar
kollo committed
77 78 79 80 81 82
#define f_hexs NULL
#define f_octs NULL
#define f_bins NULL
#define f_hashs NULL
#define f_errs NULL
#define f_envs NULL
kollo's avatar
kollo committed
83
#define f_dirs NULL
kollo's avatar
kollo committed
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
#define f_inlines NULL
#define f_radixs NULL
#define f_rightofs NULL
#define f_leftofs NULL
#define f_params NULL
#define f_mkis NULL
#define f_mkls NULL
#define f_mkss NULL
#define f_mkds NULL
#define f_mkfs NULL
#define f_aries NULL
#define f_arids NULL
#define f_bwtes NULL
#define f_bwtds NULL
#define f_compresss NULL
#define f_encloses NULL
#define f_decloses NULL
#define f_decrypts NULL
#define f_encrypts NULL
#define f_juldates NULL
#define f_mtfds NULL
#define f_mtfes NULL
kollo's avatar
kollo committed
106

kollo's avatar
kollo committed
107 108

#else
kollo's avatar
kollo committed
109 110
static STRING f_errs(int n)    { return(create_string((char *)error_text((char)n,NULL))); }
static STRING f_envs(STRING n) { return(create_string(getenv(n.pointer)));}
kollo's avatar
kollo committed
111
static STRING f_dirs(int n)    { return(create_string_and_free2(getcwd(NULL,0)));}
kollo's avatar
kollo committed
112 113 114


static STRING f_aries(STRING n) {  /* order-0 adaptive arithmetic encoding */
kollo's avatar
kollo committed
115 116 117 118
  STRING ergebnis;
  int i;
  int size=n.len;
  ergebnis.pointer=malloc(size+1);
kollo's avatar
kollo committed
119
  put_pointer=(unsigned char *)ergebnis.pointer;
kollo's avatar
kollo committed
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
  put_size=0;

  start_model();
  /* start_outputing_bits */
  buffer=0;
  bits_to_go=8;
  /* Start encoding  */
  low=0;
  high=Top_value;
  bits_to_follow=0;
    for (i=0;i<n.len;i++) {
        int ch; int symbol;
        ch=n.pointer[i]&0xff;
        symbol=char_to_index[ch];
        encode_symbol(symbol,cum_freq);
        update_model(symbol);
    }
    encode_symbol(EOF_symbol,cum_freq);
    /* done_encoding */
    bits_to_follow += 1;                        /* Output two bits that     */
    if (low<First_qtr) bit_plus_follow(0);      /* select the quarter that  */
    else bit_plus_follow(1);                    /* the current code range   */                                               /* contains.                */

  /* done_outputing_bits   */
  *put_pointer++=(buffer>>bits_to_go);
  put_size++;
  ergebnis.len=put_size;
kollo's avatar
kollo committed
147
  ergebnis.pointer[ergebnis.len]=0;
kollo's avatar
kollo committed
148 149
  return(ergebnis);
}
kollo's avatar
kollo committed
150
static STRING f_arids(STRING n) {  /* order-0 adaptive arithmetic decoding */
kollo's avatar
kollo committed
151 152 153
  STRING ergebnis;
  int j=0,i;
  int size=n.len;
kollo's avatar
kollo committed
154
  put_pointer=(unsigned char *)n.pointer;
kollo's avatar
kollo committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
  put_size=n.len;
  ergebnis.pointer=malloc(size+1);

  start_model();                              /* Set up other modules.    */

  /* start_inputing_bits */
  bits_to_go=0;
  garbage_bits=0;
  /* start_decoding   */
  value = 0;
  for(i=1;i<=Code_value_bits;i++) value=2*value+input_bit();
  low=0;
  high=Top_value;


    for (;;) {
        int ch; int symbol;
        symbol = decode_symbol(cum_freq);
        if (symbol==EOF_symbol) break;
        ch = index_to_char[symbol];

        ergebnis.pointer[j++]=ch;
        if(j>=size) {
	  size=2*(size+1);
	  ergebnis.pointer=realloc(ergebnis.pointer,size+1);
	}
        update_model(symbol);
    }
  ergebnis.len=j;
kollo's avatar
kollo committed
184
  ergebnis.pointer[ergebnis.len]=0;
kollo's avatar
kollo committed
185 186 187
  return(ergebnis);
}

kollo's avatar
kollo committed
188 189 190 191 192 193 194

static STRING f_lowers(STRING n) {   
  int i=0;
  STRING ergebnis;
  ergebnis.pointer=malloc(n.len+1);
  ergebnis.len=n.len;
  while(i<n.len) {ergebnis.pointer[i]=tolower(n.pointer[i]); i++;}
kollo's avatar
kollo committed
195
  ergebnis.pointer[ergebnis.len]=0;
kollo's avatar
kollo committed
196 197
  return(ergebnis);
}
kollo's avatar
kollo committed
198 199 200 201 202 203 204

static STRING f_uppers(STRING n) {   
  int i=0;
  STRING ergebnis;
  ergebnis.pointer=malloc(n.len+1);
  ergebnis.len=n.len;
  while(i<n.len) {ergebnis.pointer[i]=toupper(n.pointer[i]); i++;}
kollo's avatar
kollo committed
205
  ergebnis.pointer[ergebnis.len]=0;
kollo's avatar
kollo committed
206 207
  return(ergebnis);
}
kollo's avatar
kollo committed
208 209 210 211



static STRING f_trims(STRING n) {
kollo's avatar
kollo committed
212 213 214 215 216 217 218
  STRING ergebnis;
  ergebnis.pointer=malloc(n.len+1);
  xtrim(n.pointer,0,ergebnis.pointer);
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}

kollo's avatar
kollo committed
219
static STRING f_xtrims(STRING n) {
kollo's avatar
kollo committed
220 221 222 223 224 225
  STRING ergebnis;
  ergebnis.pointer=malloc(n.len+1);
  xtrim(n.pointer,1,ergebnis.pointer);
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}
kollo's avatar
kollo committed
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265


static STRING f_decloses(STRING n) {
  if(n.len>1) {
    if((*(n.pointer)=='\"' && n.pointer[n.len-1]=='\"') ||
       (*(n.pointer)=='\'' && n.pointer[n.len-1]=='\'') ||
       (*(n.pointer)=='`' && n.pointer[n.len-1]=='') ||
       (*(n.pointer)=='(' && n.pointer[n.len-1]==')') ||
       (*(n.pointer)=='[' && n.pointer[n.len-1]==']') ||
       (*(n.pointer)=='{' && n.pointer[n.len-1]=='}') ||
       (*(n.pointer)=='<' && n.pointer[n.len-1]=='>') ) {
   
      STRING ergebnis;
      ergebnis.pointer=malloc(n.len-1);
      ergebnis.len=n.len-2;
      memcpy(ergebnis.pointer,n.pointer+1,ergebnis.len);
      ergebnis.pointer[ergebnis.len]=0;
      return(ergebnis);
    } 
  }
  return(double_string(&n));
}
static STRING f_encloses(PARAMETER *plist,int e) {
  char c1='\"';
  char c2='\"';
  STRING ergebnis;
  if(e>1) {
    if(plist[1].integer>0) {
      c1=*(char *)(plist[1].pointer);
      c2=((char *)plist[1].pointer)[plist[1].integer-1];
    }
  }
  ergebnis.len=plist[0].integer+2;
  ergebnis.pointer=malloc(ergebnis.len+1);
  ergebnis.pointer[0]=c1;
  memcpy(ergebnis.pointer+1,plist->pointer,plist->integer);
  ergebnis.pointer[ergebnis.len-1]=c2;
  ergebnis.pointer[ergebnis.len]=0;
  return(ergebnis);
}
kollo's avatar
kollo committed
266
static STRING f_usings(PARAMETER *plist,int e) {
kollo's avatar
kollo committed
267 268
  if(plist->typ==PL_INT) plist->real=(double)plist->integer;
  else if(plist->typ==PL_ARBINT)  plist->real=mpz_get_d(*(ARBINT *)(plist->pointer));
kollo's avatar
kollo committed
269 270 271 272 273
  STRING form;
  form.pointer=plist[1].pointer;
  form.len=plist[1].integer;
  return(do_using(plist->real,form));
}
kollo's avatar
kollo committed
274

kollo's avatar
kollo committed
275
#ifdef CONTROL
kollo's avatar
kollo committed
276
static STRING f_csgets(STRING n) {
kollo's avatar
kollo committed
277 278 279 280 281
  STRING ergebnis;
  ergebnis.pointer=csgets(n.pointer);
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}
kollo's avatar
kollo committed
282
static STRING f_csunits(STRING n) {
kollo's avatar
kollo committed
283 284 285 286 287
  STRING ergebnis;
  ergebnis.pointer=csunit(n.pointer);
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}
kollo's avatar
kollo committed
288
static STRING f_cspnames(int n) {
kollo's avatar
kollo committed
289 290 291 292 293 294 295
  STRING ergebnis;
  ergebnis.pointer=cspname(n);
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}
#endif
#ifdef TINE
kollo's avatar
kollo committed
296
static STRING f_tinegets(STRING n) { return(tinegets(n.pointer)); }
kollo's avatar
kollo committed
297

kollo's avatar
kollo committed
298
static STRING f_tineunits(STRING n) {
kollo's avatar
kollo committed
299 300 301 302 303
  STRING ergebnis;
  ergebnis.pointer=tineunit(n.pointer);
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}
kollo's avatar
kollo committed
304
static STRING f_tineinfos(STRING n) {
kollo's avatar
kollo committed
305 306 307 308 309
  STRING ergebnis;
  ergebnis.pointer=tineinfo(n.pointer);
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}
kollo's avatar
kollo committed
310
static STRING f_tinequerys(PARAMETER *plist,int e) {
kollo's avatar
kollo committed
311 312 313 314 315
  if(e>=2) return(tinequery(plist[0].pointer,plist[1].integer));
  else return(create_string(NULL));
}
#endif
#ifdef DOOCS
kollo's avatar
kollo committed
316 317
static STRING f_doocsgets(STRING n) { return(doocsgets(n.pointer)); }
static STRING f_doocsinfos(STRING n) { return(doocsinfos(n.pointer)); }
kollo's avatar
kollo committed
318
#endif
kollo's avatar
kollo committed
319
static STRING f_terminalnames(PARAMETER *plist,int e) {
kollo's avatar
kollo committed
320
  STRING ergebnis;
kollo's avatar
kollo committed
321 322
  FILEINFO fff=get_fileptr(plist->integer);
  if(fff.typ) ergebnis.pointer=terminalname(fileno(fff.dptr));
kollo's avatar
kollo committed
323 324 325 326 327 328 329
  else {
    xberror(24,""); /* File nicht geoeffnet */
    return(vs_error());
  }
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}
kollo's avatar
kollo committed
330
static STRING f_systems(STRING n) {
kollo's avatar
kollo committed
331 332 333 334
  STRING ergebnis;
  FILE *dptr=popen(n.pointer,"r");
  if (dptr==NULL) {
    io_error(errno,"popen");
kollo's avatar
kollo committed
335
    return(vs_error());
kollo's avatar
kollo committed
336
  } else {
kollo's avatar
kollo committed
337
    int c=0,len=0;
kollo's avatar
kollo committed
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
    int limit=1024;
    ergebnis.pointer=NULL;
    do {
      ergebnis.pointer=realloc(ergebnis.pointer,limit);
     /* printf("Bufferlaenge: %d Bytes.\n",limit); */
      while(len<limit) {
        c=fgetc(dptr);
        if(c==EOF) {ergebnis.pointer[len]='\0';break;}
        ergebnis.pointer[len++]=(char)c;
      }
      limit+=len;
    } while(c!=EOF);
    if(pclose(dptr)==-1) io_error(errno,"pclose");
  }
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}
kollo's avatar
kollo committed
355
static STRING f_prgs(int n) {
kollo's avatar
kollo committed
356 357 358
  if(n>=prglen || n<0) xberror(16,"PRG$"); /* Feldindex zu gross*/
  return(create_string(program[min(prglen-1,max(n,0))]));
}
kollo's avatar
kollo committed
359
static STRING f_params(int n) {
kollo's avatar
kollo committed
360 361 362
  if(n>=param_anzahl || n<0) return(create_string(NULL));
  else return(create_string(param_argumente[min(param_anzahl-1,max(n,0))]));
}
kollo's avatar
kollo committed
363
static STRING f_unixdates(int n) {
kollo's avatar
kollo committed
364 365 366 367 368 369 370 371
  STRING ergebnis;
  struct tm * loctim;
  loctim=localtime((time_t *)(&n));
  ergebnis.pointer=malloc(12);
  sprintf(ergebnis.pointer,"%02d.%02d.%04d",loctim->tm_mday,loctim->tm_mon+1,1900+loctim->tm_year);
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}
kollo's avatar
kollo committed
372
static STRING f_unixtimes(int n) {
kollo's avatar
kollo committed
373 374 375 376 377 378 379 380
  STRING ergebnis;
  struct tm * loctim;
  loctim=localtime((time_t *)&n);
  ergebnis.pointer=malloc(16);
  sprintf(ergebnis.pointer,"%02d:%02d:%02d",loctim->tm_hour,loctim->tm_min,loctim->tm_sec);
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}
kollo's avatar
kollo committed
381
static STRING f_strs(PARAMETER *plist,int e) {         /* STR$(a[,b[,c[,d]]])     */
kollo's avatar
kollo committed
382 383 384 385 386 387 388 389 390 391
  STRING ergebnis;
  int b=-1,c=13,mode=0;
  char formatter[24];
  ergebnis.pointer=malloc(64);
  if(e>1) b=min(50,max(0,plist[1].integer));
  if(e>2) c=min(50,max(0,plist[2].integer));
  if(e>3) mode=plist[3].integer;
  if(mode==0 && b!=-1) sprintf(formatter,"%%%d.%dg",b,c);
  else if (mode==1 && b!=-1) sprintf(formatter,"%%0%d.%dg",b,c);
  else  sprintf(formatter,"%%.13g");
kollo's avatar
kollo committed
392 393 394 395 396 397 398 399
  switch(plist->typ) {
  case PL_INT:
    plist->real=(double)plist->integer;
  case PL_FLOAT:
    sprintf(ergebnis.pointer,formatter,plist->real);
    break;
  case PL_COMPLEX: {
    char *formatter2=malloc(48);
400 401 402 403 404 405 406
    if(plist->imag>=0) {
      sprintf(formatter2,"(%s+%si)",formatter,formatter);
      sprintf(ergebnis.pointer,formatter2,plist->real,plist->imag);
    } else {
      sprintf(formatter2,"(%s%si)",formatter,formatter);
      sprintf(ergebnis.pointer,formatter2,plist->real,plist->imag);
    }
kollo's avatar
kollo committed
407 408 409 410 411 412 413 414 415 416 417 418 419 420
    free(formatter2);
    }
    break;
  case PL_ARBINT: {
    char *buf=mpz_get_str(NULL,10,*(ARBINT *)(plist->pointer));
    free(ergebnis.pointer);
    ergebnis.pointer=buf;
    break;
    }
  default:
    printf("Unknown parameter typ in STR$():\n");
    dump_parameterlist(plist,e);
  }
  
kollo's avatar
kollo committed
421 422 423
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}
kollo's avatar
kollo committed
424 425 426 427 428 429 430 431


static char *i2a(unsigned i, char *a, unsigned r) {
  if(i/r>0) a=i2a(i/r,a,r);
  *a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$!?"[i % r];
  return a+1;
}

kollo's avatar
kollo committed
432
static STRING f_bins(PARAMETER *plist,int e) {
kollo's avatar
kollo committed
433
  STRING ergebnis;
kollo's avatar
kollo committed
434
  if(plist->typ==PL_INT) {
kollo's avatar
kollo committed
435
    unsigned int value=plist->integer;
kollo's avatar
kollo committed
436 437 438 439 440 441 442 443 444 445 446
    /*Predict length of string*/
    int plen=1;
    if(value) plen=(log(value)/(double)log(2))+1;
    int len=plen;
    if(e>1) len=max(plen,plist[1].integer);
    ergebnis.pointer=malloc(len+1);
    ergebnis.len=len;
    char *a=ergebnis.pointer;
    while(len>plen) {*a++='0';len--;}
    *i2a(value,a,2)=0;
    return(ergebnis);
kollo's avatar
kollo committed
447
  } 
kollo's avatar
kollo committed
448
  cast_to_arbint(plist);
kollo's avatar
kollo committed
449 450 451 452 453 454 455 456 457 458 459 460 461 462
  char *s=mpz_get_str(NULL,2,*(ARBINT *)(plist->pointer));
  int plen=strlen(s);
  int len=plen;
  if(e>1) len=max(plen,plist[1].integer);
  if(plen>=len) {
    ergebnis.pointer=s;
    ergebnis.len=plen;
    return(ergebnis);
  }
  char *a=ergebnis.pointer=malloc(len+1);
  ergebnis.len=len;
  while(len>plen) {*a++='0';len--;}
  strcpy(a,s);
  free(s);
kollo's avatar
kollo committed
463 464 465
  return(ergebnis);
}
static STRING f_octs(PARAMETER *plist,int e) {
kollo's avatar
kollo committed
466
  STRING ergebnis;  
kollo's avatar
kollo committed
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
  if(plist->typ==PL_INT) {
    unsigned int value=plist[0].integer;
    /*Predict length of string*/
    int plen=1;
    if(value) plen=(log(value)/(double)log(8))+1;
    int len=plen;
    if(e>1) len=max(plen,plist[1].integer);
    ergebnis.pointer=malloc(len+1);
    ergebnis.len=len;
    char *a=ergebnis.pointer;
    while(len>plen) {*a++='0';len--;}
    *i2a(value,a,8)=0;
    return(ergebnis);
  }
  cast_to_arbint(plist);
kollo's avatar
kollo committed
482 483 484 485 486 487 488 489 490 491 492 493 494 495
  char *s=mpz_get_str(NULL,8,*(ARBINT *)(plist->pointer));
  int plen=strlen(s);
  int len=plen;
  if(e>1) len=max(plen,plist[1].integer);
  if(plen>=len) {
    ergebnis.pointer=s;
    ergebnis.len=plen;
    return(ergebnis);
  }
  char *a=ergebnis.pointer=malloc(len+1);
  ergebnis.len=len;
  while(len>plen) {*a++='0';len--;}
  strcpy(a,s);
  free(s);
kollo's avatar
kollo committed
496 497 498 499
  return(ergebnis);
}
static STRING f_hexs(PARAMETER *plist,int e) {
  STRING ergebnis;
kollo's avatar
kollo committed
500 501 502 503 504 505 506 507 508 509
  if(plist->typ==PL_INT) {
    unsigned int value=plist[0].integer;
    /*Predict length of string*/
    int plen=1;
    if(value) plen=(int)(log((double)value)/(double)log(16))+1;
    int len=plen;
    if(e>1) len=max(plen,plist[1].integer);
    ergebnis.pointer=malloc(len+1);
    ergebnis.len=len;
    char *a=ergebnis.pointer;
kollo's avatar
kollo committed
510
 // printf("valuse=%d, len=%d, plen=%d\n",value, len,plen);
kollo's avatar
kollo committed
511
    while(len>plen) {*a++='0';len--;}
kollo's avatar
kollo committed
512
 // printf("ergebnis=<%s>\n",ergebnis.pointer);
kollo's avatar
kollo committed
513 514 515 516
    *i2a(value,a,16)=0;
    return(ergebnis);
  }
  cast_to_arbint(plist);
kollo's avatar
kollo committed
517 518 519 520 521 522 523 524 525 526 527 528 529 530
  char *s=mpz_get_str(NULL,16,*(ARBINT *)(plist->pointer));
  int plen=strlen(s);
  int len=plen;
  if(e>1) len=max(plen,plist[1].integer);
  if(plen>=len) {
    ergebnis.pointer=s;
    ergebnis.len=plen;
    return(ergebnis);
  }
  char *a=ergebnis.pointer=malloc(len+1);
  ergebnis.len=len;
  while(len>plen) {*a++='0';len--;}
  strcpy(a,s);
  free(s);
kollo's avatar
kollo committed
531 532 533
  return(ergebnis);
}

kollo's avatar
kollo committed
534 535
/*  a$=RADIX$(n%[,b%[,l%]])*/
static STRING f_radixs(PARAMETER *plist, int e) {
kollo's avatar
kollo committed
536
  STRING ergebnis;
kollo's avatar
kollo committed
537
  unsigned int base=64;
kollo's avatar
kollo committed
538
  if(e>1) base=min(62,max(2,plist[1].integer));
kollo's avatar
kollo committed
539 540 541 542 543
  if(plist->typ==PL_INT) {
    int len=0,plen=1;
    int value=plist->integer;
    int sign=1;
    if(value<0) {sign=-1;value=-value;}
kollo's avatar
kollo committed
544 545
  /*Predict length of string*/
  
kollo's avatar
kollo committed
546 547 548 549 550 551 552
    if(value) plen=(log(value)/(double)log(base))+1;
    if(sign<0) plen++;
    if(e>2) len=max(plen,plist[2].integer);
    else len=plen;
    ergebnis.pointer=malloc(len+1);
    ergebnis.len=len;
    char *a=ergebnis.pointer;
kollo's avatar
kollo committed
553
  
kollo's avatar
kollo committed
554 555 556 557 558 559
    if(sign<0) {*a++='-';len--;}
    while(len>plen) {*a++='0';len--;}
    *i2a(value,a,base)=0;
    return(ergebnis);
  }
  cast_to_arbint(plist);
kollo's avatar
kollo committed
560 561 562 563 564
  char *s=mpz_get_str(NULL,base,*(ARBINT *)(plist->pointer));
  int plen=0;
  if(!s) printf("ERROR in RADIX() base=%d\n",base);
  else plen=strlen(s);
  int len=plen;
565
  if(e>2) len=max(plen,plist[2].integer);
kollo's avatar
kollo committed
566 567 568 569 570 571 572 573 574 575 576
  if(plen>=len) {
    ergebnis.pointer=s;
    ergebnis.len=plen;
    return(ergebnis);
  }
  char *a=ergebnis.pointer=malloc(len+1);
  ergebnis.len=len;
  while(len>plen) {*a++='0';len--;}
  if(s) strcpy(a,s);
  else *a++=0;
  free(s);
kollo's avatar
kollo committed
577 578 579
  return(ergebnis);
}

kollo's avatar
kollo committed
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610


/* Gibt das i te Wort aus Zeichenkette zurueck (mit Blank getrennt, Teile in
Anfuehrungszeichen werden als ein Wort behandelt. (c) Markus Hoffmann 2010)*/
static STRING f_words(PARAMETER *plist,int e) {
  STRING ergebnis;
  int c=1,f=0,i=0,j=0,k,l=1;
  char *p,delimiter=' ';

  if(e>=3) delimiter=*(char *)plist[2].pointer;
  if(e>=2) l=plist[1].integer;
  if(e>=1) {
    k=ergebnis.len=plist->integer;
    ergebnis.pointer=malloc(ergebnis.len+1);
    p=plist->pointer;
    while(i<k) {
      if(p[i]==delimiter && !f) c++;
      else if(p[i]=='"') f=!f;
      else if(c==l) ergebnis.pointer[j++]=p[i];
      i++; 
    }
    ergebnis.pointer[j]=0;
    ergebnis.len=j;
  } else {
    ergebnis.pointer=malloc(1);
    ergebnis.len=0;
  }
  return(ergebnis);
}

static STRING f_spaces(int n) {   
kollo's avatar
kollo committed
611
  STRING ergebnis;
kollo's avatar
kollo committed
612
  int i=0; 
kollo's avatar
kollo committed
613
  if(n<0) n=0;
kollo's avatar
kollo committed
614 615 616
  ergebnis.pointer=malloc(n+1);
  ergebnis.len=n;
  while(i<n) ergebnis.pointer[i++]=' ';
kollo's avatar
kollo committed
617
  ergebnis.pointer[ergebnis.len]=0;
kollo's avatar
kollo committed
618 619
  return(ergebnis);
}
kollo's avatar
kollo committed
620 621

static STRING f_lefts(PARAMETER *plist,int e) {
kollo's avatar
kollo committed
622
  STRING ergebnis;
kollo's avatar
kollo committed
623 624 625 626 627 628 629
  int l=1;
  if(e>1) l=plist[1].integer;
  if(l>0) {
    if(l>plist->integer) l=plist->integer;
    ergebnis.len=l;
    ergebnis.pointer=malloc(l+1);
    memcpy(ergebnis.pointer,plist->pointer,l);
kollo's avatar
kollo committed
630 631 632 633
  } else {
    ergebnis.pointer=malloc(1);
    ergebnis.len=0;
  }
kollo's avatar
kollo committed
634
  ergebnis.pointer[ergebnis.len]=0;
kollo's avatar
kollo committed
635 636
  return(ergebnis);
}
kollo's avatar
kollo committed
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
static STRING f_leftofs(PARAMETER *plist,int e) {
  STRING ergebnis;
  ergebnis.len=plist->integer;
  ergebnis.pointer=malloc(ergebnis.len+1);

  if(plist->integer<=plist[1].integer) {
    memcpy(ergebnis.pointer,plist->pointer,plist->integer);
    ergebnis.pointer[ergebnis.len]=0;
  } else {
    char *t=plist->pointer;
    char *c=plist[1].pointer;
    char *w1=ergebnis.pointer;
    int i=0,j=0,f=0;
    while(i<plist->integer) {
/* suche erstes Vorkommen von c */
      while(i<plist->integer && (t[i]!=*c || f)) {
        if(t[i]=='"') f=!f;
        w1[j++]=t[i++];
      }

      if(i>=plist->integer) { /* schon am ende ? */
        w1[j]=0;
	ergebnis.len=j;
        return(ergebnis);
      } else {     /* ueberpruefe, ob auch der Rest von c vorkommt */
    
        if(memcmp(t+i,c,plist[1].integer)==0) {
          w1[j]=0;
	  ergebnis.len=j;
          return(ergebnis);
        } else {
          if(t[i]=='"') f=!f;
          w1[j++]=t[i++];
        }     /* ansonsten weitersuchen */
      }
    }
  }
  return(ergebnis);
kollo's avatar
kollo committed
675
}
kollo's avatar
kollo committed
676 677

static STRING f_rightofs(PARAMETER *plist,int e) {
kollo's avatar
kollo committed
678
  STRING ergebnis;
kollo's avatar
kollo committed
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
  ergebnis.len=plist->integer;
  ergebnis.pointer=malloc(ergebnis.len+1);

  if(plist->integer<=plist[1].integer) {
    ergebnis.len=0;
    ergebnis.pointer[ergebnis.len]=0;
  } else {
    char *t=plist->pointer;
    char *c=plist[1].pointer;
    char *w2=ergebnis.pointer;
    int i=0,f=0;
    while(i<plist->integer) {
/* suche erstes Vorkommen von c */
      while(i<plist->integer && (t[i]!=*c || f)) {
        if(t[i]=='"') f=!f;
        i++;
      }

      if(i>=plist->integer) { /* schon am ende ? */
        w2[0]=0;
	ergebnis.len=0;
        return(ergebnis);
      } else {     /* ueberpruefe, ob auch der Rest von c vorkommt */
    
        if(memcmp(t+i,c,plist[1].integer)==0) {
	  int j=0;
	  i+=plist[1].integer;
  	  while(i<plist->integer) w2[j++]=t[i++];
          w2[j]=0;
	  ergebnis.len=j;	  
          return(ergebnis);
        } else {
          if(t[i]=='"') f=!f;
          i++;
        }     /* ansonsten weitersuchen */
      }
    }
  }
  return(ergebnis);
}

static STRING f_rights(PARAMETER *plist,int e) {
kollo's avatar
kollo committed
721 722 723 724 725 726 727 728
  STRING ergebnis;
  int l=1;
  if(e>1) l=plist[1].integer;
  if(l>0) {
    if(l>plist->integer) l=plist->integer;
    ergebnis.pointer=malloc(l+1);
    ergebnis.len=l;
    memcpy(ergebnis.pointer,plist->pointer+plist->integer-l,l);
kollo's avatar
kollo committed
729 730 731 732
  } else {
    ergebnis.pointer=malloc(1);
    ergebnis.len=0;
  }
kollo's avatar
kollo committed
733
  ergebnis.pointer[ergebnis.len]=0;
kollo's avatar
kollo committed
734 735 736 737 738
  return(ergebnis);
}


static STRING f_mids(PARAMETER *plist,int e) {  
kollo's avatar
kollo committed
739 740 741 742 743 744 745 746
  STRING ergebnis;
  int l=1;
  if(e>2) l=plist[2].integer;
  int p=plist[1].integer;
  if(p==0) p=1;
  if(l>0 && p>0 && p<=plist->integer) {
    p--;
    if(p+l>plist->integer) l=plist->integer-p;
kollo's avatar
kollo committed
747 748
    ergebnis.pointer=malloc(l+1);
    ergebnis.len=l;
kollo's avatar
kollo committed
749
    memcpy(ergebnis.pointer,plist->pointer+p,l);  
kollo's avatar
kollo committed
750 751 752 753
  } else {
    ergebnis.pointer=malloc(1);
    ergebnis.len=0;
  }
kollo's avatar
kollo committed
754
  ergebnis.pointer[ergebnis.len]=0;
kollo's avatar
kollo committed
755 756 757 758
  return(ergebnis);
}

static STRING f_strings(PARAMETER *plist,int e) {
kollo's avatar
kollo committed
759 760 761 762 763 764 765 766
  STRING ergebnis;
  int j=plist->integer;
  if(j>0) {
    int i=0;
    ergebnis.len=j*plist[1].integer;    
    ergebnis.pointer=malloc(ergebnis.len+1);
    while(i<j) {memcpy(ergebnis.pointer+i*plist[1].integer,
                       plist[1].pointer,plist[1].integer); i++;}
kollo's avatar
kollo committed
767 768 769 770
  } else {
    ergebnis.pointer=malloc(1);
    ergebnis.len=0;
  }
kollo's avatar
kollo committed
771
  ergebnis.pointer[ergebnis.len]=0;
kollo's avatar
kollo committed
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
  return(ergebnis);
}

static STRING f_chrs(int n) {   
  STRING ergebnis;
  ergebnis.pointer=malloc(2);
  ergebnis.len=1;
  *ergebnis.pointer=(char)n;
  *(ergebnis.pointer+1)=0;
  return(ergebnis);
}
static STRING f_mkis(int n) {   
  STRING ergebnis;
  ergebnis.pointer=malloc(sizeof(short)+1);
  ergebnis.len=sizeof(short);
  *((short *)ergebnis.pointer)=(short)n;
  *(ergebnis.pointer+sizeof(short))=0;
  return(ergebnis);
}
static STRING f_mkls(int n) {   
  STRING ergebnis;
793 794 795 796
  ergebnis.pointer=malloc(4+1);
  ergebnis.len=4;
  *((uint32_t *)ergebnis.pointer)=(uint32_t)n;
  *(ergebnis.pointer+4)=0;
kollo's avatar
kollo committed
797 798 799 800 801 802 803 804
  return(ergebnis);
}
static STRING f_mkfs(double n) {   
  STRING ergebnis;
  ergebnis.pointer=malloc(sizeof(float)+1);
  ergebnis.len=sizeof(float);
  *((float *)ergebnis.pointer)=(float)n;
  *(ergebnis.pointer+sizeof(float))=0;
kollo's avatar
kollo committed
805 806
  return(ergebnis);
}
kollo's avatar
kollo committed
807 808 809 810 811 812 813 814 815 816
static STRING f_mkds(double n) {   
  STRING ergebnis;
  ergebnis.pointer=malloc(sizeof(double)+1);
  ergebnis.len=sizeof(double);
  *((double *)ergebnis.pointer)=n;
  *(ergebnis.pointer+sizeof(double))=0;
  return(ergebnis);
}

static STRING f_replaces(PARAMETER *plist,int e) {  /* MH 10.02.2004 */
kollo's avatar
kollo committed
817
  STRING ergebnis;
kollo's avatar
kollo committed
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
  char *pos;
  int i=0;
  int start=0;
  ergebnis.len=0;
  ergebnis.pointer=malloc(1);
  if(e==3) {
 // printf("REPLACE: <%s>--<%s>/<%s>\n",plist[0].pointer,plist[1].pointer,plist[2].pointer );

    pos=(char *)memmem(&(((char *)(plist[0].pointer))[start]),plist[0].integer-start,
                       plist[1].pointer,plist[1].integer);
    while(pos!=NULL) {         
      i=((int)(pos-(char *)plist[0].pointer))-start;     
      ergebnis.pointer=realloc(ergebnis.pointer,ergebnis.len+i+plist[2].integer);
      memcpy((char *)ergebnis.pointer+ergebnis.len,(char *)plist[0].pointer+start,i);
      memcpy((char *)ergebnis.pointer+ergebnis.len+i,(char *)plist[2].pointer,plist[2].integer);
      ergebnis.len+=i+plist[2].integer;
      start+=i+plist[1].integer;
      pos=(char *)memmem(&(((char *)(plist[0].pointer))[start]),plist[0].integer-start,
                       plist[1].pointer,plist[1].integer);
    }		       
    ergebnis.pointer=realloc(ergebnis.pointer,ergebnis.len+(plist[0].integer-start));
    memcpy((char *)ergebnis.pointer+ergebnis.len,(char *)plist[0].pointer+start,plist[0].integer-start);
    ergebnis.len+=(plist[0].integer-start);
  }
  return(ergebnis);
}

kollo's avatar
kollo committed
845 846 847

/*  Conversion from Base64 (+36) radix data to 8 Bit (Base256) binary data*/

kollo's avatar
kollo committed
848
static STRING f_inlines(STRING n) {   
kollo's avatar
kollo committed
849 850
  int l1=n.len>>2;
  int a=n.len&3;
kollo's avatar
kollo committed
851
  STRING ergebnis;
kollo's avatar
kollo committed
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869
  if(a==0) ergebnis.len=l1*3;
  else if(a==1) ergebnis.len=l1*3+1;  /* Should not happen*/
  else if(a==2) ergebnis.len=l1*3+1;  
  else  ergebnis.len=l1*3+2;  
 
  char *p=n.pointer;
  char *q=ergebnis.pointer=malloc(ergebnis.len+1);
  while(l1-->0) {
   *q++=(((p[0]-36) & 0x3f)<<2)|(((p[1]-36) & 0x30)>>4);
   *q++=(((p[1]-36) & 0xf)<<4) |(((p[2]-36) & 0x3c)>>2);
   *q++=(((p[2]-36) & 0x3)<<6) |(((p[3]-36) & 0x3f));
    p+=4;
  }
  if(a==1) *q++=(((*p-36) & 0x3f)<<2); /* soll nicht vorkommen*/
  else if(a==2) *q++=(((p[0]-36) & 0x3f)<<2)|(((p[1]-36) & 0x30)>>4);
  else if(a==3) {
    *q++=(((p[0]-36) & 0x3f)<<2)|(((p[1]-36) & 0x30)>>4);
    *q++=(((p[1]-36) & 0xf)<<4)|(((p[2]-36) & 0x3c)>>2);
kollo's avatar
kollo committed
870 871 872 873
  }
  (ergebnis.pointer)[ergebnis.len]=0;
  return(ergebnis);
}
kollo's avatar
kollo committed
874 875 876 877




kollo's avatar
kollo committed
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909
static STRING f_reverses(STRING n) {   
  int i=0;
  STRING ergebnis;
  ergebnis.pointer=malloc(n.len+1);
  ergebnis.len=n.len;
  while(i<n.len) {ergebnis.pointer[i]=n.pointer[n.len-i-1]; i++;}
  (ergebnis.pointer)[ergebnis.len]=0; 
  return(ergebnis);
}


#define IGREG 2299161
static STRING f_juldates(int n) {   
  STRING ergebnis;
  long ja,jalpha,jb;
  long day,mon,jahr;
  ergebnis.pointer=malloc(16);
  if(n>=IGREG) {
    jalpha=(long)(((float)(n-1867216)-0.25)/36524.25);
    ja=n+1+jalpha-(long)(0.25*jalpha);
  } else ja=n;
  jb=ja+1524;
  jahr=(long)(6680.0+((float)(jb-2439870)-122.1)/365.25);
  day=(long)(365*jahr+(0.25*jahr));
  mon=(long)((jb-day)/30.6001);
  day=jb-day-(long)(30.6001*mon);
  mon--;
  if(mon>12) mon-=12;
  jahr-=4715;
  if(mon>2) --jahr;
  if(jahr<=0) --jahr;
  sprintf(ergebnis.pointer,"%02d.%02d.%04d",(int)day,(int)mon,(int)jahr);
kollo's avatar
kollo committed
910 911 912
  ergebnis.len=strlen(ergebnis.pointer);
  return(ergebnis);
}
kollo's avatar
kollo committed
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
#undef IGREG



/* ************ Code Engines   ************************ */
/* *********  RLE -- Run Length Encoding/Decoding ***** */

/*  In the output stream, any two consecutive
    characters with the same value flag a run.  A byte following
    those two characters gives the count of *additional*
    repeat characters, which can be anything from 0 to 255.  */

static STRING f_rles(STRING n) {  /*Run Length Encoding*/
  int j=0,i=0;
  unsigned char c,count,last=0;
  STRING ergebnis;
  ergebnis.pointer=malloc(n.len+(int)(n.len/2)+1);
  while(i<n.len) {
    c=n.pointer[i++];
    ergebnis.pointer[j++]=c;
    if(c==last) {
      count=0;
      while(count<255 && i<n.len) {
        c=n.pointer[i++];
        if(c==last) count++;
        else break;
      }
      ergebnis.pointer[j++]=count;
      if(count!=255 && c!=last) ergebnis.pointer[j++]=c;
    }
    last=c;
  }
  ergebnis.len=j;
  (ergebnis.pointer)[ergebnis.len]=0; 
  return(ergebnis);
}
static STRING f_rlds(STRING n) {  /*Run Length Decoding*/
  int j=0,i=0;
  unsigned char c,count,last=0;
  STRING ergebnis;
 
  while(i<n.len) {        /* Laenge bestimmen : */
      c=n.pointer[i++];
      j++;
      if(c==last) {
            count=n.pointer[i++];
            j+=(count&0xff);
      }
      last=c;
  }
  last=0;
  ergebnis.pointer=malloc(j+1);
  i=j=0;
  while(i<n.len) {        /* Decodieren */
      c=n.pointer[i++];
      ergebnis.pointer[j++]=c;
      if(c==last) {
        count=n.pointer[i++];
        while(count-->0) ergebnis.pointer[j++]=c;
      }
      last=c;
  }
  ergebnis.len=j;
  (ergebnis.pointer)[ergebnis.len]=0; 
  return(ergebnis);
}


/*  An MTF encoder encodes each character using the
    count of distinct previous characters seen since the characters
    last appearance.  This is implemented by keeping an array of
    characters.  Each new input character is encoded with its
    current position in the array.  The character is then moved to
    position 0 in the array, and all the higher order characters
    are moved down by one position to make roon.
  
    Both the encoder and decoder have to start with the order array
    initialized to the same values.   */

static STRING f_mtfes(STRING n) {  /* Move To Front Encoding*/
    unsigned char order[256];
    unsigned int i,j,k;
    unsigned char c;
    STRING ergebnis;
    ergebnis.pointer=malloc(n.len+1);
    for(i=0;i<256;i++) order[i]=(unsigned char)i;
    i=0;
    while(i<n.len) {
      c=n.pointer[i];
      /* Find the char, and output it  */
     for(j=0;j<256;j++)
       if(order[j]==(c&0xff)) break;
      ergebnis.pointer[i++]=j;
          /* Now shuffle the order array  */
      for(k=j;k>0;k--) order[k]=order[k-1];
      order[0]=c;
    }  
  ergebnis.len=n.len;
  (ergebnis.pointer)[ergebnis.len]=0; 
  return(ergebnis);
}
static STRING f_mtfds(STRING n) {  /* Move To Front Decoding*/
    unsigned char order[256];
    unsigned int i,j,k;
    unsigned char c;
    STRING ergebnis;
    ergebnis.pointer=malloc(n.len+1);
    for(i=0;i<256;i++) order[i]=(unsigned char)i;
    i=0;
    while(i<n.len) {
      j=n.pointer[i] & 0xff;
      c=order[j];
      ergebnis.pointer[i++]=c;
          /* Now shuffle the order array  */
      for(k=j;k>0;k--) order[k]=order[k-1];
      order[0]=c;
    }  
  ergebnis.len=n.len;
  (ergebnis.pointer)[ergebnis.len]=0; 
  return(ergebnis);
}



static STRING f_bwtes(STRING n) {  /* Burrows-Wheeler transform*/
  STRING ergebnis;
  int indices[n.len];
  int i;
  ergebnis.pointer=malloc(n.len+1+sizeof(int));
  for(i=0;i<n.len;i++) indices[i]=i;
  rotlexcmp_buf=(unsigned char *)n.pointer;
  rottexcmp_bufsize=n.len;
  qsort(indices,n.len,sizeof(int),rotlexcmp);
  for(i=0;i<n.len;i++)
        ergebnis.pointer[i+sizeof(int)]=n.pointer[(indices[i]+n.len-1)%n.len];

  for(i=0;i<n.len;i++) {
    if(indices[i]==1) {
      *((int *)ergebnis.pointer)=i;
      break;
    }
  }
  ergebnis.len=n.len+sizeof(int);
  (ergebnis.pointer)[ergebnis.len]=0; 
  return(ergebnis);
}
static STRING f_bwtds(STRING n) {  /* inverse Burrows-Wheeler transform */
  STRING ergebnis;
kollo's avatar
kollo committed
1061 1062
  int primary_index=0;
  int size=0;   
kollo's avatar
kollo committed
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
  if(n.len>=sizeof(int)) {
    size=n.len-sizeof(int);
    primary_index=*((int *)n.pointer);
  }
  ergebnis.pointer=malloc(size+1);
  {
    unsigned char F[size];
    int buckets[256];
    int i,j,k;
    int indices[size];

    for(i=0;i<256;i++) buckets[i]=0;
    for(i=0;i<size;i++) buckets[n.pointer[sizeof(int)+i]&0xff]++;
    for(i=0,k=0;i<256;i++)
      for(j=0;j<buckets[i];j++) F[k++]=i;
kollo's avatar
kollo committed
1078 1079
    j=0;
    for(i=0;i<256;i++) {
kollo's avatar
kollo committed
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
      while(i>F[j] && j<size) j++;
      buckets[i]=j;     // it will get fake values if there is no i in F, but
                        // that won't bring us any problems
    }

    for(i=0;i<size;i++) indices[buckets[n.pointer[sizeof(int)+i]&0xff]++]=i;
    for(i=0,j=primary_index;i<size;i++) {
      ergebnis.pointer[i]=n.pointer[j+sizeof(int)];
      j=indices[j];
    }
  }
  ergebnis.len=size;
  (ergebnis.pointer)[ergebnis.len]=0; 
  return(ergebnis);
}
kollo's avatar
kollo committed
1095 1096
#ifdef HAVE_GCRYPT
  static int gcrypt_init=0;
kollo's avatar
kollo committed
1097 1098
#else
  #include "md5.h"
kollo's avatar
kollo committed
1099
  #include "sha1.h"
kollo's avatar
kollo committed
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
#endif
static STRING f_hashs(PARAMETER *plist,int e) {
  STRING ergebnis;
  int typ=1;  /*  Default is md5 */
  if(e>1) typ=plist[1].integer;
  if(typ==0 || (typ>11 && typ<301) || typ>307) typ=1;
#ifdef HAVE_GCRYPT
  if(!gcrypt_init) {
    if(!gcry_check_version(GCRYPT_VERSION)) {
      puts("ERROR: libgcrypt version mismatch\n");
    } 
    gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN);
    gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0);
    gcry_control(GCRYCTL_RESUME_SECMEM_WARN);
    gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
    gcrypt_init=1;
  }
  int hash_length = gcry_md_get_algo_dlen(typ);
  ergebnis.len=hash_length;
  ergebnis.pointer=malloc(ergebnis.len+1);
  gcry_md_hash_buffer(typ,ergebnis.pointer, plist[0].pointer, plist[0].integer);
#else
kollo's avatar
kollo committed
1122
  if(typ==1) {    /*  MD5 */
kollo's avatar
kollo committed
1123 1124 1125 1126 1127 1128 1129
    MD5_CTX ctx;
    MD5_Init(&ctx);
    MD5_Update(&ctx, plist->pointer, plist->integer);
    ergebnis.len=MD5_DIGEST_LENGTH;
    ergebnis.pointer=malloc(ergebnis.len+1);
    ergebnis.pointer[MD5_DIGEST_LENGTH]=0;
    MD5_Final((unsigned char *)ergebnis.pointer, &ctx);
kollo's avatar
kollo committed
1130 1131 1132 1133 1134 1135 1136 1137
  } else if(typ==2) {    /*  SHA1 */
    sha1_context ctx;
    sha1_starts(&ctx);
    sha1_update(&ctx, plist->pointer, plist->integer);
    ergebnis.len=SHA1_DIGEST_LENGTH;
    ergebnis.pointer=malloc(ergebnis.len+1);
    ergebnis.pointer[SHA1_DIGEST_LENGTH]=0;
    sha1_finish(&ctx, (unsigned char *)ergebnis.pointer);
kollo's avatar
kollo committed
1138 1139 1140 1141 1142 1143 1144
  } else {
    printf("The %s function is not implemented \n"
    " in this version of X11-Basic because the GCRYPT library \n"
    " was not present at compile time.\n","HASH$()");
    ergebnis.len=plist[0].integer;
    ergebnis.pointer=malloc(ergebnis.len+1);
  }
kollo's avatar
kollo committed
1145 1146 1147 1148
#endif
  (ergebnis.pointer)[ergebnis.len]=0; 
  return(ergebnis);
}
kollo's avatar
kollo committed
1149 1150


kollo's avatar
kollo committed
1151 1152 1153


static STRING do_encrypt(STRING *message, STRING *key, int typ) {
kollo's avatar
kollo committed
1154
  STRING ergebnis;
kollo's avatar
kollo committed
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
#ifdef HAVE_GCRYPT
  if(!gcrypt_init) {
    if(!gcry_check_version(GCRYPT_VERSION)) {
      puts("ERROR: libgcrypt version mismatch\n");
    } 
    gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN);
    gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0);
    gcry_control(GCRYCTL_RESUME_SECMEM_WARN);
    gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
    gcrypt_init=1;
  }
  size_t blkLength = gcry_cipher_get_algo_blklen(typ);
  size_t keyLength = gcry_cipher_get_algo_keylen(typ);
  gcry_cipher_hd_t hd;
  
kollo's avatar
kollo committed
1170 1171 1172
  if(key->len<keyLength) printf("WARNING: Key too short (%d). It must be at least %d bytes.\n",plist[1].integer,keyLength);
  if(message->len%blkLength) printf("WARNING: The message length (%d) must be a multiple of %d bytes.\n",plist[0].integer,blkLength);
  int len=(message->len-1)/blkLength+1;
kollo's avatar
kollo committed
1173 1174 1175 1176
  
    ergebnis.len=len*blkLength;
    ergebnis.pointer=malloc(ergebnis.len+1);
    gcry_cipher_open(&hd, typ, GCRY_CIPHER_MODE_CBC, 0);
kollo's avatar
kollo committed
1177
    gcry_cipher_setkey(hd,key->pointer, keyLength);
kollo's avatar
kollo committed
1178
   // gcry_cipher_setiv(hd, iniVector, blkLength);
kollo's avatar
kollo committed
1179
    int ret=gcry_cipher_encrypt(hd, ergebnis.pointer,ergebnis.len, message->pointer,len*blkLength);
kollo's avatar
kollo committed
1180 1181
    if(ret) printf("cipher failed:  %s/%s\n",gcry_strsource(ret),gcry_strerror(ret));
    gcry_cipher_close(hd);
kollo's avatar
kollo committed
1182
#else
kollo's avatar
kollo committed
1183 1184 1185
  printf("The %s function is not implemented \n"
  " in this version of X11-Basic because the GCRYPT library \n"
  " was not present at compile time.\n","ENCRYPT$()");
kollo's avatar
kollo committed
1186
  ergebnis.len=message->len;
kollo's avatar
kollo committed
1187
  ergebnis.pointer=malloc(ergebnis.len+1);
kollo's avatar
kollo committed
1188
  memcpy(ergebnis.pointer,message->pointer,ergebnis.len);
kollo's avatar
kollo committed
1189
#endif
kollo's avatar
kollo committed
1190
  (ergebnis.pointer)[ergebnis.len]=0; 
kollo's avatar
kollo committed
1191 1192
  return(ergebnis);
}
kollo's avatar
kollo committed
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217
static STRING f_encrypts(PARAMETER *plist,int e) {
  STRING ergebnis;
  int typ=4;  /*  Default is BLOWFISH */
  if(e>2) typ=plist[2].integer;
   ergebnis=do_encrypt((STRING *)&(plist[0].integer),(STRING *)&(plist[1].integer),typ);
  return(ergebnis);
}

/* 
   SIGN$(message$,key$,typ)
   Wie soll das ueberhaupt gehen?
   1. Wir berechnen einen Hash der Message z.B. mit SHA1
   2. der Hash wird nun mit dem privaten Schluessel verschluesselt
   3. der verschluesselte Hash als Signatur zurueckgeliefert.
   
   Es fehlt dann noch die Umkehrfunktion VERYFY(message$, signature$, pubkey$)
   
   */

static STRING f_signs(PARAMETER *plist,int e) {
  STRING ergebnis;
  STRING tmp;
  int typ=4;  /*  Default is BLOWFISH */
  if(e>2) typ=plist[2].integer;
  /* ALso erst einen SHA1 Hash berechnen....*/
kollo's avatar
kollo committed
1218 1219 1220 1221 1222 1223 1224
  sha1_context ctx;
  sha1_starts(&ctx);
  sha1_update(&ctx, plist->pointer, plist->integer);
  tmp.len=SHA1_DIGEST_LENGTH;
  tmp.pointer=malloc(tmp.len+1);
  tmp.pointer[SHA1_DIGEST_LENGTH]=0;
  sha1_finish(&ctx, (unsigned char *)tmp.pointer);
kollo's avatar
kollo committed
1225
  /* Jetzt verschluesseln (geht noch nicht)*/  
kollo's avatar
kollo committed
1226 1227
  ergebnis=do_encrypt(&tmp,(STRING *)&(plist[1].integer),typ);
  free_string(&tmp);
kollo's avatar
kollo committed
1228 1229 1230
  return(ergebnis);
}

kollo's avatar
kollo committed
1231
static STRING do_decrypt(STRING *message, STRING *key, int typ) {
kollo's avatar
kollo committed
1232
  STRING ergebnis;
kollo's avatar
kollo committed
1233

kollo's avatar
kollo committed
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
#ifdef HAVE_GCRYPT
  if(!gcrypt_init) {
    if(!gcry_check_version(GCRYPT_VERSION)) {
      puts("ERROR: libgcrypt version mismatch\n");
    } 
    gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN);
    gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0);
    gcry_control(GCRYCTL_RESUME_SECMEM_WARN);
    gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
    gcrypt_init=1;
  }
  size_t blkLength = gcry_cipher_get_algo_blklen(typ);
  size_t keyLength = gcry_cipher_get_algo_keylen(typ);
  gcry_cipher_hd_t hd;
  
kollo's avatar
kollo committed
1249 1250 1251
  if(key->len<keyLength) printf("WARNING: Key too short (%d). It must be at least %d bytes.\n",plist[1].integer,keyLength);
  if(message->len%blkLength) printf("WARNING: The message length (%d) must be a multiple of %d bytes.\n",plist[0].integer,blkLength);
  int len=(message->len-1)/blkLength+1;
kollo's avatar
kollo committed
1252 1253 1254 1255
  
    ergebnis.len=len*blkLength;
    ergebnis.pointer=malloc(ergebnis.len+1);
    gcry_cipher_open(&hd, typ, GCRY_CIPHER_MODE_CBC, 0);
kollo's avatar
kollo committed
1256
    gcry_cipher_setkey(hd,key->pointer, keyLength);
kollo's avatar
kollo committed
1257
   // gcry_cipher_setiv(hd, iniVector, blkLength);
kollo's avatar
kollo committed
1258
    int ret=gcry_cipher_decrypt(hd, ergebnis.pointer,ergebnis.len, message->pointer, len*blkLength);
kollo's avatar
kollo committed
1259 1260 1261
    if(ret) printf("cipherdecrypt failed:  %s/%s\n",gcry_strsource(ret),gcry_strerror(ret));
    gcry_cipher_close(hd);

kollo's avatar
kollo committed
1262
#else
kollo's avatar
kollo committed
1263 1264 1265
  printf("The %s function is not implemented \n"
  " in this version of X11-Basic because the GCRYPT library \n"
  " was not present at compile time.\n","DECRYPT$()");
kollo's avatar
kollo committed
1266
  ergebnis.len=message->len;
kollo's avatar
kollo committed
1267
  ergebnis.pointer=malloc(ergebnis.len+1);
kollo's avatar
kollo committed
1268
  memcpy(ergebnis.pointer,message->pointer,message->len);
kollo's avatar
kollo committed
1269 1270
#endif
  (ergebnis.pointer)[ergebnis.len]=0; 
kollo's avatar
kollo committed
1271 1272 1273
  return(ergebnis);
}

kollo's avatar
kollo committed
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301
static STRING f_decrypts(PARAMETER *plist,int e) {
  STRING ergebnis;
  int typ=4;  /*  Default is BLOWFISH */
  if(e>2) typ=plist[2].integer;
  ergebnis=do_decrypt((STRING *)&(plist[0].integer),(STRING *)&(plist[1].integer),typ);
  return(ergebnis);
}


int do_verify(STRING *message,STRING *signature,STRING *key, int typ) {
  /*  Erst hash der message berechnen.*/
  STRING sha1,tmp;
  int flag=1;
  sha1_context ctx;
  sha1_starts(&ctx);
  sha1_update(&ctx, (unsigned char *)message->pointer, message->len);
  sha1.len=SHA1_DIGEST_LENGTH;
  sha1.pointer=malloc(sha1.len+1);
  sha1_finish(&ctx, (unsigned char *)sha1.pointer);
  /*  Dann signatur entschluesseln*/
  tmp=do_decrypt(signature,key,typ);
  /* Dann hashes vergleichen*/
  if(tmp.len==SHA1_DIGEST_LENGTH)
    flag=memcmp(sha1.pointer,tmp.pointer,SHA1_DIGEST_LENGTH);
  free_string(&sha1);
  free_string(&tmp);
  return((flag==0)?-1:0);
}
kollo's avatar
kollo committed
1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328
static STRING f_compresss(STRING n) {
  STRING ergebnis,a,b;
  a=f_rles(n);
  b=f_bwtes(a);
  free(a.pointer);
  a=f_mtfes(b);
  free(b.pointer);
  b=f_rles(a);
  free(a.pointer);
  ergebnis=f_aries(b);
  free(b.pointer);
  return(ergebnis);
}
static STRING f_uncompresss(STRING n) {
  STRING ergebnis,a,b;
  b=f_arids(n);
  a=f_rlds(b);
  free(b.pointer);
  b=f_mtfds(a);
  free(a.pointer);
  a=f_bwtds(b);
  free(b.pointer);
  ergebnis=f_rlds(a);
  free(a.pointer);
  return(ergebnis);
}

kollo's avatar
kollo committed
1329 1330 1331 1332 1333 1334 1335 1336 1337 1338
STRING pngtobmp(unsigned char *data, size_t pngsize);
STRING bmptopng(unsigned char *data);

static STRING f_pngdecodes(STRING n) {
  return(pngtobmp((unsigned char *)n.pointer,(size_t)n.len));
}
static STRING f_pngencodes(STRING n) {  
  return(bmptopng((unsigned char *)n.pointer));
}
#endif
kollo's avatar
kollo committed
1339 1340 1341 1342 1343
const SFUNCTION psfuncs[]= {  /* alphabetisch !!! */

 { F_CONST|F_ARGUMENT,  "!nulldummy", (sfunc)f_nop ,0,0   ,{0}},
 { F_CONST|F_SQUICK,    "ARID$"     , f_arids ,1,1   ,{PL_STRING}},
 { F_CONST|F_SQUICK,    "ARIE$"     , f_aries ,1,1   ,{PL_STRING}},
kollo's avatar
kollo committed
1344
 { F_CONST|F_PLISTE,    "BIN$"      , f_bins ,1,2    ,{PL_NUMBER,PL_INT}},
kollo's avatar
kollo committed
1345 1346 1347
 { F_CONST|F_SQUICK,    "BWTD$"     , f_bwtds ,1,1   ,{PL_STRING}},
 { F_CONST|F_SQUICK,    "BWTE$"     , f_bwtes ,1,1   ,{PL_STRING}},

kollo's avatar
kollo committed
1348
 { F_CONST|F_IQUICK,    "CHR$"      , f_chrs ,1,1    ,{PL_INT}},
kollo's avatar
kollo committed
1349 1350
 { F_CONST|F_SQUICK,    "COMPRESS$" , f_compresss ,1,1   ,{PL_STRING}},
#ifdef CONTROL
kollo's avatar
kollo committed
1351 1352 1353
 { F_SQUICK,            "CSGET$"    , f_csgets ,1,1   ,{PL_STRING}},
 { F_IQUICK,            "CSPNAME$"  , f_cspnames ,1,1   ,{PL_INT}},
 { F_SQUICK,            "CSUNIT$"   , f_csunits ,1,1   ,{PL_STRING}},
kollo's avatar
kollo committed
1354
#endif
kollo's avatar
kollo committed
1355 1356 1357
 { F_CONST|F_SQUICK,    "DECLOSE$"  , f_decloses ,1,1   ,{PL_STRING}},
 { F_CONST|F_PLISTE,    "DECRYPT$"  , f_decrypts ,2,3   ,{PL_STRING,PL_STRING,PL_INT}},
 { F_IQUICK,            "DIR$"      , f_dirs ,0,1   ,{PL_INT}},
kollo's avatar
kollo committed
1358 1359 1360 1361 1362 1363
#ifdef DOOCS
 { F_SQUICK,    "DOOCSGET$"    , f_doocsgets ,1,1   ,{PL_STRING}},
 { F_SQUICK,    "DOOCSINFO$"    , f_doocsinfos ,1,1   ,{PL_STRING}},
#endif

 { F_CONST|F_PLISTE,    "ENCLOSE$" , f_encloses ,1,2   ,{PL_STRING,PL_STRING}},
kollo's avatar
kollo committed
1364
 { F_CONST|F_PLISTE,    "ENCRYPT$", f_encrypts ,2,3   ,{PL_STRING,PL_STRING,PL_INT}},
kollo's avatar
kollo committed
1365
 { F_SQUICK,    "ENV$"    , f_envs ,1,1   ,{PL_STRING}},
kollo's avatar
kollo committed
1366
 { F_CONST|F_IQUICK,    "ERR$"    , f_errs ,1,1   ,{PL_INT}},
kollo's avatar
kollo committed
1367 1368 1369 1370 1371 1372
 { F_PLISTE,    "FSFIRST$"    , f_fsfirsts ,1,3,  {PL_STRING,PL_STRING,PL_STRING} },
 { F_SIMPLE,    "FSNEXT$"    , f_fsnexts ,0,0   },


 { F_CONST|F_PLISTE,  "HASH$", f_hashs ,1,2   ,{PL_STRING,PL_INT}},

kollo's avatar
kollo committed
1373
 { F_CONST|F_PLISTE,  "HEX$"    , f_hexs ,1,2   ,{PL_NUMBER,PL_INT}},
kollo's avatar
kollo committed
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
 { F_CONST|F_SQUICK,    "INLINE$" , f_inlines ,1,1   ,{PL_STRING}},
 { F_ARGUMENT,  "INPUT$"  , f_inputs ,1,2   ,{PL_FILENR,PL_INT}},
 { F_CONST|F_IQUICK,    "JULDATE$" , f_juldates ,1,1   ,{PL_INT}},

 { F_CONST|F_PLISTE,    "LEFT$" , f_lefts ,1,2   ,{PL_STRING,PL_INT}},
 { F_CONST|F_PLISTE,    "LEFTOF$" , f_leftofs ,2,2   ,{PL_STRING,PL_STRING}},
 { F_PLISTE,    "LINEINPUT$" , f_lineinputs ,1,1   ,{PL_FILENR}},
 { F_CONST|F_SQUICK,    "LOWER$"    , f_lowers ,1,1   ,{PL_STRING}},

 { F_CONST|F_PLISTE,    "MID$"    , f_mids ,2,3   ,{PL_STRING,PL_INT,PL_INT}},
 { F_CONST|F_AQUICK,    "MKA$"    , array_to_string ,1,1   ,{PL_ARRAY}},
kollo's avatar
kollo committed
1385 1386
 { F_CONST|F_DQUICK,    "MKD$"    , f_mkds ,1,1   ,{PL_FLOAT}},
 { F_CONST|F_DQUICK,    "MKF$"    , f_mkfs ,1,1   ,{PL_FLOAT}},
kollo's avatar
kollo committed
1387 1388
 { F_CONST|F_IQUICK,    "MKI$"    , f_mkis ,1,1   ,{PL_INT}},
 { F_CONST|F_IQUICK,    "MKL$"    , f_mkls ,1,1   ,{PL_INT}},
kollo's avatar
kollo committed
1389
 { F_CONST|F_DQUICK,    "MKS$"    , f_mkfs ,1,1   ,{PL_FLOAT}},
kollo's avatar
kollo committed
1390 1391 1392
 { F_CONST|F_SQUICK,    "MTFD$"  , f_mtfds ,1,1   ,{PL_STRING}},
 { F_CONST|F_SQUICK,    "MTFE$"  , f_mtfes ,1,1   ,{PL_STRING}},

kollo's avatar
kollo committed
1393
 { F_CONST|F_PLISTE,  "OCT$"    , f_octs ,1,2   ,{PL_NUMBER,PL_INT}},
kollo's avatar
kollo committed
1394 1395

 { F_IQUICK,    "PARAM$"  , f_params ,1,1   ,{PL_INT}},
kollo's avatar
kollo committed
1396 1397 1398 1399
 
 { F_CONST|F_SQUICK,    "PNGDECODE$"  , f_pngdecodes ,1,1   ,{PL_STRING}},
 { F_CONST|F_SQUICK,    "PNGENCODE$"  , f_pngencodes ,1,1   ,{PL_STRING}},
 
kollo's avatar
kollo committed
1400 1401 1402
 { F_CONST|F_IQUICK,    "PRG$"    , f_prgs ,1,1   ,{PL_INT}},
 { F_CONST|F_PLISTE,    "REPLACE$"  , f_replaces ,3,3   ,{PL_STRING,PL_STRING,PL_STRING}},
 { F_CONST|F_SQUICK,    "REVERSE$"  , f_reverses ,1,1   ,{PL_STRING}},
kollo's avatar
kollo committed
1403
 { F_CONST|F_PLISTE,    "RADIX$"    , f_radixs ,1,3   ,{PL_NUMBER,PL_INT,PL_INT}},
kollo's avatar
kollo committed
1404 1405 1406 1407 1408
 { F_CONST|F_PLISTE,    "RIGHT$"  , f_rights ,1,2   ,{PL_STRING,PL_INT}},
 { F_CONST|F_PLISTE,    "RIGHTOF$" , f_rightofs ,2,2   ,{PL_STRING,PL_STRING}},
 { F_CONST|F_SQUICK,    "RLD$"  , f_rlds ,1,1   ,{PL_STRING}},
 { F_CONST|F_SQUICK,    "RLE$"  , f_rles ,1,1   ,{PL_STRING}},

kollo's avatar
kollo committed
1409
 { F_CONST|F_PLISTE,  "SIGN$", f_signs ,2,3   ,{PL_STRING,PL_STRING,PL_INT}},
kollo's avatar
kollo committed
1410 1411
/* bei STRING$ und SPACE$ machen wir kein F_CONST*/
 { F_IQUICK,    "SPACE$"  , f_spaces ,1,1   ,{PL_INT}},
kollo's avatar
kollo committed
1412
 { F_CONST|F_PLISTE,  "STR$"    , f_strs ,1,4   ,{PL_NUMBER,PL_INT,PL_INT,PL_INT}},
kollo's avatar
kollo committed
1413 1414
/* bei STRING$ und SPACE$ machen wir kein F_CONST*/
 { F_PLISTE,  "STRING$" , f_strings ,2,2   ,{PL_INT,PL_STRING}},
kollo's avatar
kollo committed
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429
 { F_SQUICK,    "SYSTEM$"    , f_systems ,1,1   ,{PL_STRING}},
 { F_PLISTE,    "TERMINALNAME$"    , f_terminalnames ,1,1 ,{PL_FILENR}},
#ifdef TINE
 { F_SQUICK,    "TINEGET$"    , f_tinegets ,1,1   ,{PL_STRING}},
 { F_SQUICK,    "TINEINFO$"   , f_tineinfos ,1,1   ,{PL_STRING}},
 { F_PLISTE,    "TINEQUERY$"  , f_tinequerys ,2,2   ,{PL_STRING,PL_INT}},
 { F_SQUICK,    "TINEUNIT$"   , f_tineunits ,1,1   ,{PL_STRING}},
#endif
 { F_CONST|F_SQUICK,    "TRIM$"   , f_trims ,1,1   ,{PL_STRING}},

 { F_CONST|F_SQUICK,    "UCASE$"    , f_uppers ,1,1   ,{PL_STRING}},
 { F_CONST|F_SQUICK,    "UNCOMPRESS$" , f_uncompresss ,1,1   ,{PL_STRING}},
 { F_CONST|F_IQUICK,    "UNIXDATE$" , f_unixdates ,1,1   ,{PL_INT}},
 { F_CONST|F_IQUICK,    "UNIXTIME$" , f_unixtimes ,1,1   ,{PL_INT}},
 { F_CONST|F_SQUICK,    "UPPER$"    , f_uppers ,1,1   ,{PL_STRING}},
kollo's avatar
kollo committed
1430
 { F_CONST|F_PLISTE,    "USING$"    , f_usings ,2,2   ,{PL_NUMBER,PL_STRING}},
kollo's avatar
kollo committed
1431 1432 1433 1434
 { F_CONST|F_PLISTE,    "WORD$"    , f_words ,2,3   ,{PL_STRING,PL_INT,PL_STRING}},
 { F_CONST|F_SQUICK,    "XTRIM$"   , f_xtrims ,1,1   ,{PL_STRING}}
};
const int anzpsfuncs=sizeof(psfuncs)/sizeof(SFUNCTION);