00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <ctype.h>
00012 #include <errno.h>
00013 #include <fcntl.h>
00014 #include <stdlib.h>
00015 #include <string.h>
00016 #include <stdio.h>
00017 #ifndef WIN32
00018 #include <poll.h>
00019 #include <unistd.h>
00020 #include <strings.h>
00021 #if !defined(__linux__) && !defined(__CYGWIN__)
00022 #ifdef __FreeBSD__
00023 #include <sys/param.h>
00024 #endif
00025 #include <sys/conf.h>
00026 #endif
00027 #include <sys/stat.h>
00028 #include <sys/termios.h>
00029 #include <sys/types.h>
00030 #include <sys/wait.h>
00031 #else // WIN32
00032 #include "XrdSys/XrdWin32.hh"
00033 #include <process.h>
00034 #endif // WIN32
00035
00036 #include "XrdOuc/XrdOucEnv.hh"
00037 #include "XrdOuc/XrdOucStream.hh"
00038 #include "XrdOuc/XrdOucUtils.hh"
00039 #include "XrdSys/XrdSysHeaders.hh"
00040 #include "XrdSys/XrdSysLogger.hh"
00041 #include "XrdSys/XrdSysPlatform.hh"
00042
00043
00044
00045
00046
00047 #define MaxARGC 64
00048 #define XrdOucStream_EOM 0x01
00049 #define XrdOucStream_BUSY 0x02
00050
00051 #define Erq(p, a, b) Err(p, a, b, (char *)0)
00052 #define Err(p, a, b, c) (ecode=(Eroute ? Eroute->Emsg(#p, a, b, c) : a), -1)
00053 #define Erp(p, a, b, c) ecode=(Eroute ? Eroute->Emsg(#p, a, b, c) : a)
00054
00055
00056
00057 #define Erx(p, a, b) if (Eroute) cerr <<#p <<' ' <<strerror(a) <<' ' <<b <<endl;
00058
00059
00060
00061
00062
00063 XrdOucStream::XrdOucStream(XrdSysError *erobj, const char *ifname,
00064 XrdOucEnv *anEnv, const char *Pfx)
00065 {
00066 char *cp;
00067 if (ifname)
00068 {myInst = strdup(ifname);
00069 if (!(cp = index(myInst, ' '))) {cp = myInst; myExec = 0;}
00070 else {*cp = '\0'; cp++;
00071 myExec = (*myInst ? myInst : 0);
00072 }
00073 if ((myHost = index(cp, '@')))
00074 {*myHost = '\0';
00075 myHost++;
00076 myName = (*cp ? cp : 0);
00077 } else {myHost = cp; myName = 0;}
00078 } else myInst = myHost = myName = myExec = 0;
00079
00080 FD = -1;
00081 FE = -1;
00082 bsize = 0;
00083 buff = 0;
00084 bnext = 0;
00085 bleft = 0;
00086 recp = 0;
00087 token = 0;
00088 flags = 0;
00089 child = 0;
00090 ecode = 0;
00091 notabs = 0;
00092 xcont = 1;
00093 xline = 0;
00094 Eroute = erobj;
00095 myEnv = anEnv;
00096 sawif = 0;
00097 skpel = 0;
00098 if (myEnv && Eroute)
00099 {llBuff = (char *)malloc(llBsz);
00100 llBcur = llBuff; llBok = 0; llBleft = llBsz; *llBuff = '\0';
00101 Verbose= 1;
00102 } else {
00103 Verbose= 0;
00104 llBuff = 0;
00105 llBcur = 0;
00106 llBleft= 0;
00107 llBok = 0;
00108 }
00109 varVal = (myEnv ? new char[maxVLen+1] : 0);
00110 llPrefix = Pfx;
00111 }
00112
00113
00114
00115
00116
00117 int XrdOucStream::AttachIO(int infd, int outfd, int bsz)
00118 {
00119 if (Attach(infd, bsz)) return -1;
00120 FE = outfd;
00121 return 0;
00122 }
00123
00124 int XrdOucStream::Attach(int FileDescriptor, int bsz)
00125 {
00126
00127
00128
00129 Close();
00130
00131
00132
00133 if (!bsz) buff = 0;
00134 else if (!(buff = (char *)malloc(bsz+1)))
00135 return Erq(Attach, errno, "allocate stream buffer");
00136
00137
00138
00139 FD= FE = FileDescriptor;
00140 bnext = buff;
00141 bsize = bsz+1;
00142 bleft = 0;
00143 recp = 0;
00144 token = 0;
00145 flags = 0;
00146 ecode = 0;
00147 xcont = 1;
00148 xline = 0;
00149 sawif = 0;
00150 skpel = 0;
00151 if (llBuff)
00152 {llBcur = llBuff; *llBuff = '\0'; llBleft = llBsz; llBok = 0;}
00153 return 0;
00154 }
00155
00156
00157
00158
00159
00160 void XrdOucStream::Close(int hold)
00161 {
00162
00163
00164
00165 if (!hold) Drain();
00166 else child = 0;
00167
00168
00169
00170 if (FD >= 0) close(FD);
00171 if (FE >= 0 && FE != FD) close(FE);
00172
00173
00174
00175 if (buff) free(buff);
00176
00177
00178
00179 FD = FE = -1;
00180 buff = 0;
00181
00182
00183
00184 if (llBuff && Verbose && Eroute)
00185 {if (*llBuff && llBok > 1) Eroute->Say(llPrefix, llBuff);
00186 llBok = 0;
00187 }
00188 }
00189
00190
00191
00192
00193
00194 int XrdOucStream::Drain()
00195 {
00196 int Status = 0;
00197
00198
00199
00200 #ifndef WIN32
00201 int retc;
00202 if (child) {kill(-child, 9);
00203 do {retc = waitpid(child, &Status, 0);}
00204 while(retc > 0 || (retc == -1 && errno == EINTR));
00205 child = 0;
00206 }
00207 #else
00208 if (child) {
00209 TerminateProcess((HANDLE)child, 0);
00210 child = 0;
00211 }
00212 #endif
00213 return Status;
00214 }
00215
00216
00217
00218
00219
00220 void XrdOucStream::Echo()
00221 {
00222 if (llBok && Verbose && *llBuff && Eroute) Eroute->Say(llPrefix, llBuff);
00223 llBok = 0;
00224 }
00225
00226
00227
00228
00229
00230 int XrdOucStream::Exec(const char *theCmd, int inrd, int efd)
00231 {
00232 int j;
00233 char *cmd, *origcmd, *parm[MaxARGC];
00234
00235
00236
00237 origcmd = cmd = (char *)malloc(strlen(theCmd)+1);
00238 strcpy(cmd, theCmd);
00239
00240
00241
00242 for (j = 0; j < MaxARGC-1 && *cmd; j++)
00243 {while(*cmd == ' ') cmd++;
00244 if (!(*cmd)) break;
00245 parm[j] = cmd;
00246 while(*cmd && *cmd != ' ') cmd++;
00247 if (*cmd) {*cmd = '\0'; cmd++;}
00248 }
00249 parm[j] = (char *)0;
00250
00251
00252
00253 j = Exec(parm, inrd, efd);
00254 free(origcmd);
00255 return j;
00256 }
00257
00258 int XrdOucStream::Exec(char **parm, int inrd, int efd)
00259 {
00260 int fildes[2], Child_in = -1, Child_out = -1, Child_log = -1;
00261
00262
00263
00264 if (inrd >= 0)
00265 {if (pipe(fildes))
00266 return Err(Exec, errno, "create input pipe for", parm[0]);
00267 else {
00268 fcntl(fildes[0], F_SETFD, FD_CLOEXEC);
00269 Attach(fildes[0]); Child_out = fildes[1];
00270 }
00271
00272 if (inrd)
00273 {if (pipe(fildes))
00274 return Err(Exec, errno, "create output pipe for", parm[0]);
00275 else {
00276 fcntl(fildes[1], F_SETFD, FD_CLOEXEC);
00277 FE = fildes[1]; Child_in = fildes[0];
00278 }
00279 }
00280 } else {Child_out = FD; Child_in = FE;}
00281
00282
00283
00284 if (!efd) Child_log = (Eroute ? dup(Eroute->logger()->originalFD()) : -1);
00285 else if (efd > 0) Child_log = efd;
00286
00287
00288
00289
00290 if ((child = fork()))
00291 { close(Child_out);
00292 if (inrd) close(Child_in );
00293 if (!efd && Child_log >= 0) close(Child_log);
00294 if (child < 0)
00295 return Err(Exec, errno, "fork request process for", parm[0]);
00296 setpgid(child, child);
00297 return 0;
00298 }
00299
00300
00301
00302
00303
00304
00305
00306 if (Child_in >= 0)
00307 {if (inrd)
00308 {if (dup2(Child_in, STDIN_FILENO) < 0)
00309 {Erx(Exec, errno, "set up standard in for " <<parm[0]);
00310 exit(255);
00311 } else if (Child_in != Child_out) close(Child_in);
00312 }
00313 }
00314
00315
00316
00317 if (Child_out >= 0)
00318 {if (dup2(Child_out, STDOUT_FILENO) < 0)
00319 {Erx(Exec, errno, "set up standard out for " <<parm[0]);
00320 exit(255);
00321 } else close(Child_out);
00322 }
00323
00324
00325
00326 if (Child_log >= 0)
00327 {if (dup2(Child_log, STDERR_FILENO) < 0)
00328 {Erx(Exec, errno, "set up standard err for " <<parm[0]);
00329 exit(255);
00330 } else close(Child_log);
00331 }
00332
00333
00334
00335
00336 setpgid(0,0);
00337 execv(parm[0], parm);
00338 Erx(Exec, errno, "execute " <<parm[0]);
00339 exit(255);
00340 }
00341
00342
00343
00344
00345
00346 char *XrdOucStream::GetLine()
00347 {
00348 int bcnt, retc;
00349 char *bp;
00350
00351
00352
00353 if (flags & XrdOucStream_EOM) return (char *)NULL;
00354
00355
00356
00357 if (bleft > 0)
00358 {recp = bnext; bcnt = bleft;
00359 for (bp = bnext; bcnt--; bp++)
00360 if (!*bp || *bp == '\n')
00361 {if (!*bp) flags |= XrdOucStream_EOM;
00362 *bp = '\0';
00363 bnext = ++bp;
00364 bleft = bcnt;
00365 token = recp;
00366 return recp;
00367 }
00368 else if (notabs && *bp == '\t') *bp = ' ';
00369
00370
00371
00372 strncpy(buff, bnext, bleft);
00373 bnext = buff + bleft;
00374 }
00375 else bnext = buff;
00376
00377
00378
00379 bcnt = bsize - (bnext - buff) -1;
00380 bp = bnext;
00381
00382
00383
00384
00385 recp = token = buff;
00386 while(bcnt)
00387 {do { retc = read(FD, (void *)bp, (size_t)bcnt); }
00388 while (retc < 0 && errno == EINTR);
00389
00390 if (retc < 0) {Erp(GetLine,errno,"read request",0); return (char *)0;}
00391 if (!retc)
00392 {*bp = '\0';
00393 flags |= XrdOucStream_EOM;
00394 bnext = ++bp;
00395 bleft = 0;
00396 return buff;
00397 }
00398
00399 bcnt -= retc;
00400 while(retc--)
00401 if (!*bp || *bp == '\n')
00402 {if (!*bp) flags |= XrdOucStream_EOM;
00403 else *bp = '\0';
00404 bnext = ++bp;
00405 bleft = retc;
00406 return buff;
00407 } else {
00408 if (notabs && *bp == '\t') *bp = ' ';
00409 bp++;
00410 }
00411 }
00412
00413
00414
00415 Erp(GetLine, EMSGSIZE, "read full message", 0);
00416 buff[bsize-1] = '\0';
00417 return buff;
00418 }
00419
00420
00421
00422
00423
00424 char *XrdOucStream::GetToken(int lowcase) {
00425 char *tpoint;
00426
00427
00428
00429 if (!token) return (char *)NULL;
00430
00431
00432
00433 while (*token && *token == ' ') token ++;
00434 if (!*token) {token = 0; return 0;}
00435 tpoint = token;
00436
00437
00438
00439 if (lowcase) while (*token && *token != ' ')
00440 {*token = (char)tolower((int)*token); token++;}
00441 else while (*token && *token != ' ') {token++;}
00442 if (*token) {*token = '\0'; token++;}
00443
00444
00445
00446 return tpoint;
00447 }
00448
00449 char *XrdOucStream::GetToken(char **rest, int lowcase)
00450 {
00451 char *tpoint;
00452
00453
00454
00455 if (!(tpoint = GetToken(lowcase))) return tpoint;
00456
00457
00458
00459 while (*token && *token == ' ') token ++;
00460 if (rest) *rest = token;
00461
00462
00463
00464
00465 return tpoint;
00466 }
00467
00468
00469
00470
00471
00472 char *XrdOucStream::GetFirstWord(int lowcase)
00473 {
00474
00475
00476
00477 if (xline)
00478 {XrdOucEnv *oldEnv = SetEnv(0);
00479 while(GetWord(lowcase));
00480 SetEnv(oldEnv);
00481 }
00482 return GetWord(lowcase);
00483 }
00484
00485
00486
00487
00488
00489 char *XrdOucStream::GetMyFirstWord(int lowcase)
00490 {
00491 char *var;
00492 int skip2fi = 0;
00493
00494
00495 if (llBok > 1 && Verbose && *llBuff && Eroute) Eroute->Say(llPrefix,llBuff);
00496 llBok = 0;
00497
00498 if (!myInst)
00499 {if (!myEnv) return add2llB(GetFirstWord(lowcase), 1);
00500 else {while((var = GetFirstWord(lowcase)) && !isSet(var)) {}
00501 return add2llB(var, 1);
00502 }
00503 }
00504
00505 do {if (!(var = GetFirstWord(lowcase)))
00506 {if (sawif)
00507 {ecode = EINVAL;
00508 if (Eroute) Eroute->Emsg("Stream", "Missing 'fi' for last 'if'.");
00509 }
00510 return add2llB(var, 1);
00511 }
00512
00513 if ( !strcmp("if", var)) var = doif();
00514 if (var && !strcmp("else", var)) var = doelse();
00515 if (var && !strcmp("fi", var))
00516 {if (sawif) sawif = skpel = skip2fi = 0;
00517 else {if (Eroute)
00518 Eroute->Emsg("Stream", "No preceeding 'if' for 'fi'.");
00519 ecode = EINVAL;
00520 }
00521 continue;
00522 }
00523 if (var && (!myEnv || !isSet(var))) return add2llB(var, 1);
00524 } while (1);
00525
00526 return 0;
00527 }
00528
00529
00530
00531
00532
00533 char *XrdOucStream::GetWord(int lowcase)
00534 {
00535 char *wp, *ep;
00536
00537
00538
00539 xline = 1;
00540 while((wp = GetToken(lowcase)))
00541 {if (!myEnv) return add2llB(wp);
00542 if ((wp = vSubs(wp)) && *wp) return add2llB(wp);
00543 }
00544
00545
00546
00547 if (!xcont) {xcont = 1; xline = 0; return (char *)0;}
00548
00549
00550
00551 while(GetLine())
00552 {
00553
00554 if (!(wp = GetToken(lowcase))) continue;
00555
00556
00557
00558 if (*wp == '#') continue;
00559
00560
00561
00562 ep = bnext-2;
00563 while (ep >= buff && *ep == ' ') ep--;
00564 if (ep < buff) continue;
00565 if (*ep == '\\') {xcont = 1; *ep = '\0';}
00566 else xcont = 0;
00567 return add2llB((myEnv ? vSubs(wp) : wp));
00568 }
00569 xline = 0;
00570 return (char *)0;
00571 }
00572
00573
00574
00575
00576
00577 int XrdOucStream::GetRest(char *theBuff, int Blen, int lowcase)
00578 {
00579 char *tp, *myBuff = theBuff;
00580 int tlen;
00581
00582
00583
00584 theBuff[0] = '\0';
00585 while ((tp = GetWord(lowcase)))
00586 {tlen = strlen(tp);
00587 if (tlen+1 >= Blen) return 0;
00588 if (myBuff != theBuff) {*myBuff++ = ' '; Blen--;}
00589 strcpy(myBuff, tp);
00590 Blen -= tlen; myBuff += tlen;
00591 }
00592
00593
00594
00595 add2llB(0);
00596 return 1;
00597 }
00598
00599
00600
00601
00602
00603 void XrdOucStream::RetToken()
00604 {
00605
00606
00607 if (!token || token == recp) return;
00608
00609
00610
00611 while(*token && token != recp) token--;
00612 if (token != recp)
00613 {if (token+1 != bnext) *token = ' ';
00614 token--;
00615 while(*token && *token != ' ' && token != recp) token--;
00616 if (token != recp) token++;
00617 }
00618
00619
00620
00621 if (llBuff)
00622 while(llBcur != llBuff && *llBcur != ' ') {llBcur--; llBleft++;}
00623 }
00624
00625
00626
00627
00628
00629 int XrdOucStream::Put(const char *data, const int dlen) {
00630 int dcnt = dlen, retc;
00631
00632 if (flags & XrdOucStream_BUSY) {ecode = ETXTBSY; return -1;}
00633
00634 while(dcnt)
00635 {do { retc = write(FE, (const void *)data, (size_t)dlen);}
00636 while (retc < 0 && errno == EINTR);
00637 if (retc >= 0) dcnt -= retc;
00638 else {flags |= XrdOucStream_BUSY;
00639 Erp(Put, errno, "write to stream", 0);
00640 flags &= ~XrdOucStream_BUSY;
00641 return -1;
00642 }
00643 }
00644 return 0;
00645 }
00646
00647 int XrdOucStream::Put(const char *datavec[], const int dlenvec[]) {
00648 int i, retc, dlen;
00649 const char *data;
00650
00651 if (flags & XrdOucStream_BUSY) {ecode = ETXTBSY; return -1;}
00652
00653 for (i = 0; datavec[i]; i++)
00654 {data = datavec[i]; dlen = dlenvec[i];
00655 while(dlen)
00656 {do { retc = write(FE, (const void *)data, (size_t)dlen);}
00657 while (retc < 0 && errno == EINTR);
00658 if (retc >= 0) {data += retc; dlen -= retc;}
00659 else {flags |= XrdOucStream_BUSY;
00660 Erp(Put, errno, "write to stream",0);
00661 flags &= ~XrdOucStream_BUSY;
00662 return -1;
00663 }
00664 }
00665 }
00666 return 0;
00667 }
00668
00669
00670
00671
00672
00673 int XrdOucStream::Wait4Data(int msMax)
00674 {
00675 struct pollfd polltab = {FD, POLLIN|POLLRDNORM, 0};
00676 int retc;
00677
00678
00679
00680 do {retc = poll(&polltab, 1, msMax);} while(retc < 0 && errno == EINTR);
00681 if (retc != 1) return (retc ? errno : -1);
00682
00683
00684
00685 return (polltab.revents & (POLLIN|POLLRDNORM) ? 0 : EIO);
00686 }
00687
00688
00689
00690
00691
00692
00693
00694
00695 char *XrdOucStream::add2llB(char *tok, int reset)
00696 {
00697 int tlen;
00698
00699
00700
00701 if (!llBuff) return tok;
00702
00703
00704
00705 if (reset)
00706 {llBok = 1;
00707 llBcur = llBuff;
00708 llBleft= llBsz;
00709 *llBuff = '\0';
00710 } else if (!llBok) return tok;
00711 else {llBok = 2;
00712 if (llBleft >= 2)
00713 {*llBcur++ = ' '; *llBcur = '\0'; llBleft--;}
00714 }
00715
00716
00717
00718 if (tok)
00719 {tlen = strlen(tok);
00720 if (tlen < llBsz)
00721 {strcpy(llBcur, tok); llBcur += tlen; llBleft -= tlen;}
00722 }
00723 return tok;
00724 }
00725
00726
00727
00728
00729 char *XrdOucStream::doelse()
00730 {
00731 char *var;
00732
00733
00734
00735 if (!sawif || sawif == 2)
00736 {if (Eroute) Eroute->Emsg("Stream", "No preceeding 'if' for 'else'.");
00737 ecode = EINVAL;
00738 return 0;
00739 }
00740
00741
00742
00743 if (skpel)
00744 {while((var = GetFirstWord()))
00745 {if (!strcmp("fi", var)) return var;}
00746 if (Eroute) Eroute->Emsg("Stream", "Missing 'fi' for last 'if'.");
00747 ecode = EINVAL;
00748 return 0;
00749 }
00750
00751
00752
00753 do {if (!(var = GetWord()))
00754 {sawif = 2;
00755 return 0;
00756 }
00757 if (strcmp("if", var))
00758 {Eroute->Emsg("Stream","'else",var,"' is invalid.");
00759 ecode = EINVAL;
00760 return 0;
00761 }
00762 sawif = 0;
00763 var = doif();
00764 } while(var && !strcmp("else", var));
00765 return var;
00766 }
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793 char *XrdOucStream::doif()
00794 {
00795 char *var;
00796 int rc;
00797
00798
00799
00800 if (sawif)
00801 {if (Eroute) Eroute->Emsg("Stream", "Missing 'fi' for last 'if'.");
00802 ecode = EINVAL;
00803 }
00804
00805
00806
00807 sawif = 1; skpel = 0;
00808 if ((rc = XrdOucUtils::doIf(Eroute,*this,"if directive",myHost,myName,myExec)))
00809 {if (rc < 0) ecode = EINVAL;
00810 else skpel = 1;
00811 return 0;
00812 }
00813
00814
00815
00816 while((var = GetFirstWord()))
00817 {if (!strcmp("fi", var)) return var;
00818 if (!strcmp("else", var)) return var;
00819 }
00820
00821
00822
00823 if (!var)
00824 {if (Eroute) Eroute->Emsg("Stream", "Missing 'fi' for last 'if'.");
00825 ecode = EINVAL;
00826 }
00827 return 0;
00828 }
00829
00830
00831
00832
00833
00834 int XrdOucStream::isSet(char *var)
00835 {
00836 static const char *Mtxt1[2] = {"setenv", "set"};
00837 static const char *Mtxt2[2] = {"Setenv variable", "Set variable"};
00838 static const char *Mtxt3[2] = {"Variable", "Environmental variable"};
00839 char *tp, *vn, *vp, *pv, Vname[64], ec, Nil = 0;
00840 int sawEQ, Set = 1;
00841
00842
00843
00844 if (!strcmp("setenv", var)) Set = 0;
00845 else if (strcmp("set", var)) return 0;
00846
00847
00848
00849 if (!(tp = GetToken()))
00850 return xMsg("Missing variable name after '",Mtxt1[Set],"'.");
00851
00852
00853
00854 if (Set)
00855 {if (!strcmp(tp, "-q")) {if (llBuff) {free(llBuff); llBuff = 0;}; return 1;}
00856 if (!strcmp(tp, "-v") || !strcmp(tp, "-V"))
00857 {if (Eroute)
00858 {if (!llBuff) llBuff = (char *)malloc(llBsz);
00859 llBcur = llBuff; llBok = 0; llBleft = llBsz; *llBuff = '\0';
00860 Verbose = (strcmp(tp, "-V") ? 1 : 2);
00861 }
00862 return 1;
00863 }
00864 }
00865
00866
00867
00868 if ((vp = index(tp, '='))) {sawEQ = 1; *vp = '\0'; vp++;}
00869 else sawEQ = 0;
00870 if (strlcpy(Vname, tp, sizeof(Vname)) >= sizeof(Vname))
00871 return xMsg(Mtxt2[Set],tp,"is too long.");
00872 if (!Set && !strncmp("XRD", Vname, 3))
00873 return xMsg("Setenv variable",tp,"may not start with 'XRD'.");
00874
00875
00876
00877 tp = Vname;
00878 while (*tp && isalnum(*tp)) tp++;
00879 if (*tp) return xMsg(Mtxt2[Set], Vname, "is non-alphanumeric");
00880
00881
00882
00883 if (sawEQ) tp = vp;
00884 else if (!(tp = GetToken()) || *tp != '=')
00885 return xMsg("Missing '=' after", Mtxt1[Set], Vname);
00886 else tp++;
00887 if (!*tp && !(tp = GetToken())) tp = (char *)"";
00888
00889
00890
00891
00892 if (*tp != '$') vp = tp;
00893 else {pv = tp+1;
00894 if (*pv == '(') ec = ')';
00895 else if (*pv == '{') ec = '}';
00896 else if (*pv == '[') ec = ']';
00897 else ec = 0;
00898 if (!ec) vn = tp+1;
00899 else {while(*pv && *pv != ec) pv++;
00900 if (*pv) *pv = '\0';
00901 else ec = 0;
00902 vn = tp+2;
00903 }
00904 if (!*vn) {*pv = ec; return xMsg("Variable", tp, "is malformed.");}
00905 if (!(vp = (Set ? getenv(vn) : myEnv->Get(vn))))
00906 {if (ec != ']')
00907 {xMsg(Mtxt3[Set],vn,"is undefined."); *pv = ec; return 1;}
00908 vp = &Nil;
00909 }
00910 *pv = ec;
00911 }
00912
00913
00914
00915 if ((int)strlen(vp) > maxVLen)
00916 return xMsg(Mtxt3[Set], Vname, "value is too long.");
00917
00918
00919
00920 if (Verbose == 2 && Eroute)
00921 if (!(pv = (Set ? myEnv->Get(Vname) : getenv(Vname))) || strcmp(vp, pv))
00922 {char vbuff[1024];
00923 strcpy(vbuff, Mtxt1[Set]); strcat(vbuff, " "); strcat(vbuff, Vname);
00924 Eroute->Say(vbuff, " = ", vp);
00925 }
00926 if (Set) myEnv->Put(Vname, vp);
00927 else if (!(pv = getenv(Vname)) || strcmp(vp,pv))
00928 XrdOucEnv::Export(Vname, vp);
00929 return 1;
00930 }
00931
00932
00933
00934
00935
00936 char *XrdOucStream::vSubs(char *Var)
00937 {
00938 char *vp, *sp, *dp, *vnp, ec, bkp, valbuff[maxVLen], Nil = 0;
00939 int n;
00940
00941
00942
00943 if (!Var) return Var;
00944 sp = Var; dp = valbuff; n = maxVLen-1; *varVal = '\0';
00945
00946 while(*sp && n > 0)
00947 {if (*sp == '\\') {*dp++ = *(sp+1); sp +=2; n--; continue;}
00948 if (*sp != '$'
00949 || (!isalnum(*(sp+1)) && !index("({[", *(sp+1))))
00950 {*dp++ = *sp++; n--; continue;}
00951 sp++; vnp = sp;
00952 if (*sp == '(') ec = ')';
00953 else if (*sp == '{') ec = '}';
00954 else if (*sp == '[') ec = ']';
00955 else ec = 0;
00956 if (ec) {sp++; vnp++;}
00957 while(isalnum(*sp)) sp++;
00958 if (ec && *sp != ec)
00959 {xMsg("Variable", vnp-2, "is malformed."); return varVal;}
00960 bkp = *sp; *sp = '\0';
00961 if (!(vp = myEnv->Get(vnp)))
00962 {if (ec != ']') xMsg("Variable", vnp, "is undefined.");
00963 vp = &Nil;
00964 }
00965 while(n && *vp) {*dp++ = *vp++; n--;}
00966 if (*vp) break;
00967 if (ec) sp++;
00968 else *sp = bkp;
00969 }
00970
00971 if (*sp) xMsg("Substituted text too long using", Var);
00972 else {*dp = '\0'; strcpy(varVal, valbuff);}
00973 return varVal;
00974 }
00975
00976
00977
00978
00979
00980 int XrdOucStream::xMsg(const char *txt1, const char *txt2, const char *txt3)
00981 {
00982 if (Eroute) Eroute->Emsg("Stream", txt1, txt2, txt3);
00983 ecode = EINVAL;
00984 return 1;
00985 }