示例#1
0
LVal parse_attr(char* str) {
  int i,j;
  char *name,*val;
  struct Cons tmp,*ret=&tmp,*cur=ret;
  struct opts* p;
  tmp.next=(LVal)NULL;
  for(i=0;str[i]!='\0';++i) {
    name=NULL,val=NULL;
    /*skip space*/
    int pos=position_char_not(" \t\r\n",&str[i]);
    if(pos!=-1) {
      i+=pos;
    }else continue;
    /*attr name */
    pos=position_char("\"'>/= \t\r\n",&str[i]);
    if(pos!=-1)
      name=subseq(&str[i],0,pos),i+=pos;
    /*skip space*/
    pos=position_char_not(" \t\r\n",&str[i]);
    if(pos!=-1)
      i+=pos;
    if(!(name && str[i]=='='))
      continue;
    cur->next=(LVal)attralloc();;
    p=(struct opts*)firstp((LVal)cur->next);
    p->name=name;
    /*skip space*/
    pos=position_char_not(" \t\r\n",&str[++i]);
    if(pos!=-1) {
      i+=pos;
      switch(str[i]) {
      case '\'':
        j=position_char("'",&str[i+1]);
        if(j!=-1) {
          val=subseq(&str[i+1],0,j);
          i+=j+1;
        }
        break;
      case '"':
        for(j=1;str[i+j]!='"';++j)
          if(str[i+j]=='\\')
            ++j;
        val=subseq(&str[i],1,j);
        i+=j;
        break;
      default:
        pos=position_char(" \t\r\n",&str[i]);
        val=subseq(&str[i],0,pos);
        break;
      }
      p->value=val;
    }
    cur=(struct Cons *)cur->next;
  }
  return (LVal)ret->next;
}
示例#2
0
static size_t header_callback(char *buffer, size_t size,size_t nitems, int *opt) {
  int pos=-1,pos2,code=0;
  if(strncmp("HTTP",buffer,nitems<4?nitems:4)==0) {
    pos=position_char(" ",buffer);
    if(pos!=-1 && (pos2=position_char_not("0123456789",&buffer[pos+1]))!=-1) {
      char *num=subseq(&buffer[pos+1],0,pos2);
      code=atoi(num),s(num);
      if(verbose)
        fprintf(c_out, "http response:%d\n",code);
    }
    if(400<=code)
      return 0; /*invoke error for curl*/
  }else if(strncmp("content-length:",downcase(buffer),nitems<15?nitems:15)==0) {
    pos=position_char(" ",buffer);
    if(pos!=-1 && (pos2=position_char_not("0123456789",&buffer[pos+1]))!=-1) {
      char *num=subseq(&buffer[pos+1],0,pos2);
      code=atoi(num),s(num);
      content_length=code;
    }
  }
  return nitems * size;
}
示例#3
0
char* determin_impl(char* impl) {
  char* version=NULL;
  int pos;
  cond_printf(1,"determin_impl:%s\n",impl);
  if(impl && (pos=position_char("/",impl))!=-1) {
    version=subseq(impl,pos+1,0);
    impl=subseq(impl,0,pos);
  }else {
    if(!impl)
      impl=get_opt("default.lisp",1);
    if(impl) {
      char* opt=s_cat(q(impl),q("."),q("version"),NULL);
      version=get_opt(opt,1);
      s(opt);
    }
    if(!impl)
      impl=DEFAULT_IMPL;
    impl=q(impl);
    if(version)
      version=q(version);
  }
  if(!version&&strcmp(impl,DEFAULT_IMPL)!=0) {
    cond_printf(1,"once!%s,%s\n",impl,version);
    if(!version)
      s(version);
    version=q("system");
  }

  if(!(impl && version)) {
    char* cmd=cat(which(argv_orig[0]),verbose>0?(verbose>1?" -v -v":" -v"):""," setup",NULL);
    char* ret;
    if(impl) s(impl);
    impl=q(DEFAULT_IMPL);
    cond_printf(1,"cmd:%s\n",cmd);
    ret=system_(cmd);
    cond_printf(1,"ret:%s\n",ret);
    s(ret);
    char* path=s_cat(configdir(),q("config"),NULL);
    global_opt=load_opts(path),s(path);;
    version=get_opt(DEFAULT_IMPL".version",0);
  }
  return s_cat(impl,q("/"),version,NULL);
}
示例#4
0
char* which(char* cmd) {
#ifndef HAVE_WINDOWS_H
  char* which_cmd=cat("command -v \"",cmd,"\"",NULL);
#else
  if((cmd[0]=='.' && cmd[1]=='/')|| /* relative path */
     position_char("/:",cmd)!=-1) { /* have no path element */
    cmd=substitute_char('\\','/',q(cmd));
    return truename(cmd);
  }
  char* which_cmd=cat("cmd /c where ",cmd,"",NULL);
#endif
  cond_printf(1,"which cmd:%s\n",which_cmd);
  char* p=system_(which_cmd);
  cond_printf(1,"which result:%s\n",p);
  p=substitute_char('\0','\r',substitute_char('\0','\n',p));
  char* p2=p?remove_char("\r\n",p):q("");
  s(p),s(which_cmd);
  return p2;
}
int sbcl_bin_expand(struct install_options* param) {
  char* impl=param->impl;
  char* version=q(param->version);
  int ret;
  char* home=configdir();
  char* arch= arch_(param);
  char* archive=cat(impl,"-",version,"-",arch,".msi",NULL);
  char* log_path=cat(home,"impls",SLASH,"log",SLASH,impl,"-",version,"-",arch,SLASH,"install.log",NULL);
  char* dist_path;
  int pos=position_char("-",impl);
  if(pos!=-1) {
    impl=subseq(impl,0,pos);
  }else
    impl=q(impl);
  dist_path=cat(home,"src",SLASH,impl,"-",version,"-",arch,SLASH,NULL);
  printf("Extracting the msi archive. %s to %s\n",archive,dist_path);
  archive=s_cat(q(home),q("archives"),q(SLASH),archive,NULL);
  delete_directory(dist_path,1);
  ensure_directories_exist(dist_path);
  ensure_directories_exist(log_path);
  if(dist_path[strlen(dist_path)-1]=='\\')
    dist_path[strlen(dist_path)-1]='\0';

  char* cmd=cat("msiexec.exe /a \"",
                archive,
                "\" targetdir=\"",
                dist_path,
                "\" /qn /lv ",
                "\"",
                log_path,
                "\"",
                NULL);
  cmd=cat("cmd /c \"",cmd,"\"",NULL);
  cond_printf(1,"msiexeccmd:%s\n",cmd);
  ret=System(cmd);
  s(impl);
  s(dist_path);
  s(log_path);
  s(archive);
  s(cmd),s(home),s(version),s(arch);
  return !ret;
}
示例#6
0
int install_help(int argc,char **argv,struct sub_command* cmd) {
  if(argc==1) {
    cond_printf(0,"Usage: %s install impl [OPTIONS]\n\nFor more details on impl specific options, type:\n %s help install impl\n\n"
                "Candidates impls for installation are:\n",argv_orig[0],argv_orig[0]);
    char* install=lispdir();
    LVal d=directory(install),v=d;
    for(;v;v=Next(v)) {
      char* str=firsts(v);
      if(str[strlen(str)-1]!='/') {
        int p=position_char(".",str);
        if(p!=-1) {
          char *sub=subseq(str,0,p);
          if(p>=8/*strlen("install-")*/ && strncmp(str,"install-",8)==0)
            printf("%s\n",sub+8);
          s(sub);
        }
      }
    }
    sL(d);
  }else if(argc==2) {
    int i,j,argc_;
    char** tmp;
    char* install_ros=s_cat2(lispdir(),q("install.ros"));
    tmp=(char**)alloc(sizeof(char*)*(argc+9));
    i=0;
    tmp[i++]=q("--");
    tmp[i++]=install_ros;
    tmp[i++]=q("help");
    tmp[i++]=q(argv[1]);
    for(j=2;j<argc;tmp[i++]=q(argv[j++]));
    argc_=i;
    for(i=0;i<argc_;i+=proccmd(argc_-i,&tmp[i],top_options,top_commands));
    for(j=0;j<argc_;s(tmp[j++]));
    dealloc(tmp);
  }
  return 0;
}
示例#7
0
int cmd_run_star(int argc,char **argv,struct sub_command* cmd) {
  int ret=1;
  char* config=configdir();
  set_opt(&local_opt,"quicklisp",s_escape_string(cat(config,"impls",SLASH,"ALL",SLASH,"ALL",SLASH,"quicklisp",SLASH,NULL)),0);
  set_opt(&local_opt,"argv0",argv_orig[0],0);
  set_opt(&local_opt,"wargv0",which(argv_orig[0]),0);
  set_opt(&local_opt,"homedir",config,0);
  if(rc) {
    char* init=s_cat(configdir(),q("init.lisp"),NULL);
#ifdef _WIN32
    char* etc="";
#else
    char* etc="/etc/rosrc";
#endif
    char* current=get_opt("program",0);
    char *path,*would;
    if(file_exist_p(init)) {
      path=cat("(:load \"",init,"\")",NULL);
      would=cat(path,current?current:"",NULL);
      s(current);
      set_opt(&local_opt,"program",would,0);
      s(path);
    }
    s(init);
    current=get_opt("program",0);
    if(file_exist_p(etc)) {
      path=cat("(:load \"",etc,"\")",NULL);
      would=cat(path,current?current:"",NULL);
      set_opt(&local_opt,"program",would,0);
    }
  }
  char*lisp=get_opt("lisp",1);
  if(!lisp)
    lisp=get_opt("*lisp",0);
  set_opt(&local_opt,"impl",determin_impl(lisp),0);
  char** arg=NULL;
  int i;
  char* wrap=get_opt("wrap",1);
  {
    struct sub_command cmd;
    int i;
    char *_= get_opt("impl",0);
    i=position_char("/",_);
    cmd.name=subseq(_,0,i);
    cmd.short_name=subseq(_,i+1,0);
    for(i=0;i<sizeof(impls_to_run)/sizeof(struct run_impl_t);++i)
      if(strcmp(impls_to_run[i].name,cmd.name)==0) {
        arg=impls_to_run[i].impl(argc,argv,&cmd);
        break;
      }
    s((char*)cmd.name),s((char*)cmd.short_name);
  }
  if(wrap)
    arg[0]=q(wrap);
  if(arg && file_exist_p(arg[1])) {
    char* opts=sexp_opts(local_opt);
    setenv("ROS_OPTS",opts,1);
    if(verbose&1 ||testing) {
      fprintf(stderr,"args ");
      for(i=0;arg[i]!=NULL;++i)
        fprintf(stderr,"%s ",arg[i]);
      fprintf(stderr,"\nROS_OPTS %s\n",getenv("ROS_OPTS"));
      if(testing)
        s(opts),exit(EXIT_SUCCESS);
    }
    s(opts);
#ifdef _WIN32
    {
      char* cmd=q(arg[wrap?0:1]);
      for(i=wrap?1:2;arg[i]!=NULL;++i) {
        cmd=s_cat(cmd,q(" "),q("\""),escape_string(arg[i]),q("\""),NULL);
      }
      SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
      exit(System(cmd));
      s(cmd);
    }
#else
    execvp(arg[wrap?0:1],&(arg[wrap?0:1]));
#endif
  }else
    fprintf(stderr,"%s is not installed.stop.\n",get_opt("impl",0));

  s(config);
  return ret;
}
示例#8
0
int cmd_install(int argc,char **argv,struct sub_command* cmd) {
  install_cmds *cmds=NULL;
  struct install_options param;
  quicklisp=1;
  param.os=uname();
  param.arch=uname_m();
  param.arch_in_archive_name=0;
  param.expand_path=NULL;
  if(argc!=1) {
    int ret=1,k;
    for(k=1;k<argc;++k) {
      int i,pos;
      param.impl=argv[k];
      pos=position_char("/",param.impl);
      if(pos!=-1) {
        param.version=subseq(param.impl,pos+1,0);
        param.impl=subseq(param.impl,0,pos);
      }else {
        param.version=NULL;
        param.impl=q(param.impl);
      }

      for(install_impl=NULL,i=0;i<sizeof(impls_to_install)/sizeof(struct install_impls*);++i) {
        struct install_impls* j=impls_to_install[i];
        if(strcmp(param.impl,j->name)==0) {
          install_impl=j;
        }
      }
      if(install_impl) {
        for(cmds=install_impl->call;*cmds&&ret;++cmds)
          ret=(*cmds)(&param);
        if(ret) { // after install latest installed impl/version should be default for 'run'
          struct opts* opt=global_opt;
          struct opts** opts=&opt;
          char* home=configdir();
          char* path=cat(home,"config",NULL);
          char* v=cat(param.impl,".version",NULL);
          char* version=param.version;
          if(!install_impl->util) {
            int i;
            for(i=0;version[i]!='\0';++i)
              if(version[i]=='-')
                version[i]='\0';
            set_opt(opts,"default.lisp",param.impl,0);
            set_opt(opts,v,version,0);
            save_opts(path,opt);
          }
          s(home),s(path),s(v);
        }
      }else {
        char* lisp_path=lispdir();
        int i,j,argc_;
        char** tmp;
        char* install_ros=s_cat2(lisp_path,q("install.ros"));
        if(verbose&1) {
          fprintf(stderr,"%s is not implemented internal. %s argc:%d\n",param.impl,install_ros,argc);
          for(i=0;i<argc;++i)
            fprintf(stderr,"%s:",argv[i]);
          fprintf(stderr,"\n");
        }
        tmp=(char**)alloc(sizeof(char*)*(argc+9));
        i=0;
        tmp[i++]=q("--");
        tmp[i++]=install_ros;
        tmp[i++]=q("install");
        tmp[i++]=q(argv[1]);
        for(j=2;j<argc;tmp[i++]=q(argv[j++]));
        argc_=i;
        if(verbose&1) {
          int j;
          fprintf(stderr,"argc_=%d",argc_);
          for(j=0;j<argc_;++j)
            fprintf(stderr,"argv[%d]=%s,",j,tmp[j]);
        }
        for(i=0;i<argc_;i+=proccmd(argc_-i,&tmp[i],top_options,top_commands));
        for(j=0;j<argc_;s(tmp[j++]));
        dealloc(tmp);
        return 0;
      }
      if(param.version)s(param.version);
      s(param.impl),s(param.arch),s(param.os);
      s(param.expand_path);
      if(!ret)
        exit(EXIT_FAILURE);
    }
  }else {
    char* tmp[]={"help","install"};
    proccmd(2,tmp,top_options,top_commands);
    exit(EXIT_SUCCESS);
  }
  return 0;
}
示例#9
0
/* return value:
 *  0 success
 * -1 fopen failed
 * -2 curl initialization failed
 * -3 scheme is neither http nor https
 * -4 faild to parse the URL (InternetCrackUrl) (windows)
 * -5 https responce status is not HTTP_STATUS_OK (windows)
 * -6 HttpQueryInfo failed (windows)
 * -7 rename failure
 */
int download_simple (char* uri,char* path,int opt) {
  FILE *bodyfile;
  char* path_partial=cat(path,".partial",NULL);
  bodyfile = fopen(path_partial,"wb");
  if (bodyfile == NULL) {
    s(path_partial);
    return -1;
  }
  c_out=0==(download_opt=opt)?stderr:stdout;
#ifndef HAVE_WINDOWS_H
  CURL *curl;
  CURLcode res=!CURLE_OK;
  curl = curl_easy_init();
  if(curl) {
    char* current=get_opt("ros.proxy",1);
    if(current) {
      /*<[protocol://][user:password@]proxyhost[:port]>*/
      char *reserve=current,*protocol=NULL,*userpwd=NULL,*port=NULL,*uri=NULL;
      int pos=position_char("/",current);
      if(pos>0 && current[pos-1]==':' && current[pos+1]=='/')
        protocol=current,current[pos-1]='\0',current=current+pos+2;
      pos=position_char("@",current);
      if(pos!=-1)
        userpwd=current,current[pos]='\0',current=current+pos+1;
      pos=position_char(":",current);
      if(pos!=-1)
        current[pos]='\0',port=current+pos+1,uri=current;
      curl_easy_setopt(curl, CURLOPT_PROXY, uri);
      if(port)
        curl_easy_setopt(curl, CURLOPT_PROXYPORT,atoi(port));
      if(userpwd)
        curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, userpwd);
      s(reserve);
    }
    count=0,content_length=0;
    curl_easy_setopt(curl, CURLOPT_URL, uri);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
    curl_easy_setopt(curl,CURLOPT_WRITEDATA,bodyfile);
    res = curl_easy_perform(curl);
    if(res != CURLE_OK && verbose) {
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));
    }
    curl_easy_cleanup(curl);
    fclose(bodyfile);
  }
  if(res != CURLE_OK)
    return -2;
#else
  URL_COMPONENTS u;
  TCHAR szHostName[4096];
  TCHAR szUrlPath[4096];

  u.dwStructSize = sizeof(u);
  u.dwSchemeLength    = 1;
  u.dwHostNameLength  = 4096;
  u.dwUserNameLength  = 1;
  u.dwPasswordLength  = 1;
  u.dwUrlPathLength   = 4096;
  u.dwExtraInfoLength = 1;

  u.lpszScheme     = NULL;
  u.lpszHostName   = szHostName;
  u.lpszUserName   = NULL;
  u.lpszPassword   = NULL;
  u.lpszUrlPath    = szUrlPath;
  u.lpszExtraInfo  = NULL;
  if(!InternetCrackUrl(uri,(DWORD)strlen(uri),0,&u)) {
    fclose(bodyfile);
    return -4;
  }
  HINTERNET hSession = InternetOpen("WinInet",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);
  HINTERNET hConnection = InternetConnect(hSession,szHostName,u.nPort,NULL,NULL,INTERNET_SERVICE_HTTP,0,0);
  DWORD dwFlags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE;
  if(INTERNET_SCHEME_HTTP == u.nScheme) {
  }else if( INTERNET_SCHEME_HTTPS == u.nScheme ) {
    dwFlags = dwFlags | INTERNET_FLAG_SECURE| INTERNET_FLAG_IGNORE_CERT_DATE_INVALID| INTERNET_FLAG_IGNORE_CERT_CN_INVALID;
  }else {
    fclose(bodyfile);
    return -3;
  }
  HINTERNET hRequest = HttpOpenRequest(hConnection,"GET",szUrlPath,NULL,NULL,NULL,dwFlags,0);

  HttpSendRequest(hRequest,NULL,0,NULL,0);
  DWORD dwStatusCode,dwContentLen;
  DWORD dwLength = sizeof(DWORD);
  if(HttpQueryInfo(hRequest,HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,&dwContentLen,&dwLength,0))
    content_length=dwContentLen;
  if(!HttpQueryInfo(hRequest,HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER,&dwStatusCode,&dwLength,0)) {
    fclose(bodyfile);
    return -6;
  }
  if(HTTP_STATUS_OK != dwStatusCode) {
    fclose(bodyfile);
    return -5;
  }
  char pData[10000];
  DWORD dwBytesRead = 1;
  count=0;
  while (dwBytesRead) {
    InternetReadFile(hRequest, pData, 99, &dwBytesRead);
    pData[dwBytesRead] = 0;
    write_data(pData,dwBytesRead,1,bodyfile);
  }
  fclose(bodyfile);
#endif
  fprintf(c_out, "\n");
  int ret=rename_file(path_partial,path);
  s(path_partial);
  return ret?0:-7;
}
示例#10
0
int download_simple (char* uri,char* path,int opt) {
  FILE *bodyfile;
  char* path_partial=cat(path,".partial",NULL);
  bodyfile = fopen(path_partial,"wb");
  if (bodyfile == NULL) {
    s(path_partial);
    return 1;
  }
  download_out=0==(download_opt=opt)?stderr:stdout;

  CURL *curl;
  CURLcode res=!CURLE_OK;
  curl = curl_easy_init();
  if(curl) {
    char* current=get_opt("ros.proxy",1);
    int lenuri=strlen(uri);
    int https=(lenuri>5 && strncmp("https",uri,5)==0);
    int httponly= get_opt("proxy.http.only",0) && strcmp(get_opt("proxy.http.only",0),"1")==0;
    if(current&& ((https && !httponly) || !https)) {
      /*<[protocol://][user:password@]proxyhost[:port]>*/
      char *reserve,*protocol=NULL,*userpwd=NULL,*port=NULL,*uri=NULL;
      int pos=position_char("/",current);
      reserve=current=q_(current);
      if(pos>0 && current[pos-1]==':' && current[pos+1]=='/')
        protocol=current,current[pos-1]='\0',current=current+pos+2;
      pos=position_char("@",current);
      if(pos!=-1)
        userpwd=current,current[pos]='\0',current=current+pos+1;
      pos=position_char(":",current);
      if(pos!=-1)
        current[pos]='\0',port=current+pos+1,uri=current;
      cond_printf(1,"proxy uri=%s",uri);
      curl_easy_setopt(curl, CURLOPT_PROXY, uri);
      if(port) {
        cond_printf(1," port=%s",port);
        curl_easy_setopt(curl, CURLOPT_PROXYPORT,atoi(port));
      }
      if(userpwd)
        curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, userpwd);
      cond_printf(1,"\n");
      s(reserve);
    }
    download_count=0,content_length=0;
    curl_easy_setopt(curl, CURLOPT_URL, uri);
    curl_easy_setopt(curl, CURLOPT_USERAGENT, PACKAGE_STRING);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
    curl_easy_setopt(curl,CURLOPT_WRITEDATA,bodyfile);
    res = curl_easy_perform(curl);
    if(res != CURLE_OK && verbose) {
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));
    }
    curl_easy_cleanup(curl);
    fclose(bodyfile);
  }
  if(res != CURLE_OK)
    return 2;
  fprintf(download_out, "\n");
  int ret=rename_file(path_partial,path);
  s(path_partial);
  return ret?0:7;
}
示例#11
0
LVal parse_tags(FILE* fp,LVal before,int mode) {
  LVal current=tagalloc();
  char str[2]={'\0','\0'};
  int c,i=0;
  char* buf=q("");
  switch(mode) {
  case 0: /* wait for '<' */
    ((struct tag*)firstp(current))->type=0;
    while((c=fgetc(fp))!=EOF) {
      if(c=='<') {
        if(strlen(buf)==0) {
          tagfree(current);
          s(buf);
          return parse_tags(fp,before,1);
        }else {
          ((struct Cons*)current)->next=parse_tags(fp,current,1);
          s(buf);
          return current;
        }
      }else
        str[0]=c,buf=s_cat2(buf,q(str));
    }
    break;
  case 1: /* wait for '>' */
    ((struct tag*)firstp(current))->type=0;
    while((c=fgetc(fp))!=EOF) {
      if(i==0) {
        if(c=='/')
          ((struct tag*)firstp(current))->type=2;
        else {
          ((struct tag*)firstp(current))->type=1;
          str[0]=c;
          buf=s_cat2(buf,q(str));
        }
        ++i;
        continue;
      }
      if(c=='>') {
        char *buf2;
        if(((struct tag*)firstp(current))->type==2) {
          int pos=position_char(" \t\r\n",buf);
          if(pos!=-1) {
            buf2=subseq(buf,0,pos);
            s(buf);
            buf=buf2;
            ((struct tag*)firstp(current))->name=q(buf);
          }else {
            ((struct tag*)firstp(current))->name=buf;
            buf=q("");
          }
        }else if(((struct tag*)firstp(current))->type==1) {
          int pos=position_char(" \t\r\n",buf);
          if(pos!=-1) {
            ((struct tag*)firstp(current))->name=subseq(buf,0,pos);
            buf2=subseq(buf,pos,0);
            ((struct tag*)firstp(current))->attr=(struct Cons*)parse_attr(buf2);
            s(buf);
            buf=buf2;
          }else {
            ((struct tag*)firstp(current))->name=buf;
            buf=q("");
          }
        }
        if(strcmp(((struct tag*)firstp(current))->name,"script")==0) {
          ((struct Cons*)current)->next=parse_tags(fp,current,2);
        }else{
          ((struct Cons*)current)->next=parse_tags(fp,current,0);
        }
        s(buf);
        return current;
      }else {
        str[0]=c;
        buf=s_cat2(buf,q(str));
      }
      ++i;
    }
    break;
  case 2: /* wait for '</' */
    ((struct tag*)firstp(current))->type=0;
    while((c=fgetc(fp))!=EOF) {
      if(c=='<') {
        if((c=fgetc(fp))!=EOF && c=='/') {
          ungetc('/',fp);
          if(strlen(buf)==0) {
            tagfree(current);
            s(buf);
            return parse_tags(fp,current,1);
          }else {
            ((struct Cons*)current)->next=parse_tags(fp,current,1);
            s(buf);
            return current;
          }
        }
        ungetc('/',fp);
      }else {
        str[0]=c;
        buf=s_cat2(buf,q(str));
      }
    }
    break;
  }
  s(buf);
  return current;
}