示例#1
0
文件: q2_7.c 项目: vdloo/SICP
node *find_intersection(node *first_node_pointer, node *second_node_pointer) {
    node *first_tail = first_node_pointer, *second_tail = second_node_pointer;
    int first_length = 0, second_length = 0, i;
    find_tail(first_tail, first_length, first_node_pointer);
    find_tail(second_tail, second_length, second_node_pointer);
    if (first_tail != second_tail) {
        /* If the tails do not point to the same memory location,
         * then there is no intersection. If there was an intersection
         * both linked lists would end in the same node (they can have
         * different beginnings but must have the same end) */
        return NULL;
    }
    if (first_length > second_length) {
        first_node_pointer = fast_forward(
            first_node_pointer, first_length - second_length
        );
    } else {
        second_node_pointer = fast_forward(
            second_node_pointer, second_length - first_length
        );
    }
    while (first_node_pointer != NULL  && second_node_pointer != NULL) {
        if (first_node_pointer == second_node_pointer) {
            return first_node_pointer;
        }
        first_node_pointer = first_node_pointer->next;
        second_node_pointer = second_node_pointer->next;
    }
    fprintf(
        stderr, "Fell of the end of one of the linked lists! That should "
                "never happen, you made a programming error!\n"
    );
    exit(1);
}
示例#2
0
int
nr_ice_peer_ctx_parse_media_stream_attribute(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *attr)
{
    int r,_status;
    char *orig = 0;
    char *str;

    orig = str = attr;

    if (!strncasecmp(str, "ice-ufrag:", 10)) {
      fast_forward(&str, 10);
      if (*str == '\0')
        ABORT(R_BAD_DATA);

      skip_whitespace(&str);
      if (*str == '\0')
        ABORT(R_BAD_DATA);

      if ((r=grab_token(&str, &stream->ufrag)))
        ABORT(r);
    }
    else if (!strncasecmp(str, "ice-pwd:", 8)) {
      fast_forward(&str, 8);
      if (*str == '\0')
        ABORT(R_BAD_DATA);

      skip_whitespace(&str);
      if (*str == '\0')
        ABORT(R_BAD_DATA);

      if ((r=grab_token(&str, &stream->pwd)))
        ABORT(r);
    }
    else {
      ABORT(R_BAD_DATA);
    }

    skip_whitespace(&str);

    /* RFC 5245 grammar doesn't have an extension point for ice-pwd or
       ice-ufrag: if there's anything left on the line, we treat it as bad. */
    if (str[0] != '\0') {
      ABORT(R_BAD_DATA);
    }

    _status=0;
  abort:
    if (_status) {
      if (orig)
        r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Error parsing attribute: %s",pctx->label,orig);
    }

    return(_status);
}
示例#3
0
int
nr_ice_peer_ctx_parse_media_stream_attribute(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *attr)
{
    int r,_status;
    char *orig = 0;
    char *str;

    orig = str = attr;

    if (!strncasecmp(str, "ice-ufrag:", 10)) {
      fast_forward(&str, 10);
      if (*str == '\0')
        ABORT(R_BAD_DATA);

      skip_whitespace(&str);
      if (*str == '\0')
        ABORT(R_BAD_DATA);

      if ((r=grab_token(&str, &stream->ufrag)))
        ABORT(r);
    }
    else if (!strncasecmp(str, "ice-pwd:", 8)) {
      fast_forward(&str, 8);
      if (*str == '\0')
        ABORT(R_BAD_DATA);

      skip_whitespace(&str);
      if (*str == '\0')
        ABORT(R_BAD_DATA);

      if ((r=grab_token(&str, &stream->pwd)))
        ABORT(r);
    }
    else {
      ABORT(R_BAD_DATA);
    }

    skip_whitespace(&str);
    /* it's expected to be at EOD at this point */

    assert(strlen(str) == 0);

    _status=0;
  abort:
    if (_status) {
      if (orig)
        r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Error parsing attribute: %s",pctx->label,orig);
    }

    return(_status);
}
示例#4
0
void task_scheduler(void)
{
	int i;
	timestamp_t now;

	task_started = 1;

	while (1) {
		now = get_time();
		i = TASK_ID_COUNT - 1;
		while (i >= 0) {
			/*
			 * Only tasks with spawned threads are valid to be
			 * resumed.
			 */
			if (tasks[i].thread) {
				if (tasks[i].event ||
				    now.val >= tasks[i].wake_time.val)
					break;
			}
			--i;
		}
		if (i < 0)
			i = fast_forward();

		tasks[i].wake_time.val = ~0ull;
		running_task_id = i;
		tasks[i].started = 1;
		pthread_cond_signal(&tasks[i].resume);
		pthread_cond_wait(&scheduler_cond, &run_lock);
	}
}
示例#5
0
int main()
{
    struct item *dll = create_dll();
    fast_forward(&dll);
    ___sl_plot("03-ff-done");

    return 0;
}
示例#6
0
int main()
{
    struct item *dll = create_dll();
    __VERIFIER_plot("01-before-fast-forward");

    fast_forward(&dll);
    __VERIFIER_plot("02-after-fast-forward");

    return 0;
}
示例#7
0
int
nr_ice_peer_ctx_parse_global_attributes(nr_ice_peer_ctx *pctx, char **attrs, int attr_ct)
{
    int r,_status;
    int i;
    char *orig = 0;
    char *str;
    char *component_id;
    char *connection_address;
    unsigned int port;
    in_addr_t addr;
    char *ice_option_tag;

    for(i=0;i<attr_ct;i++){
        orig = str = attrs[i];

        component_id = 0;
        connection_address = 0;
        ice_option_tag = 0;

        if (!strncasecmp(str, "remote-candidates:", 18)) {
            fast_forward(&str, 18);
            skip_whitespace(&str);

            while (*str != '\0') {
                if ((r=grab_token(&str, &component_id)))
                    ABORT(r);

                if (*str == '\0')
                    ABORT(R_BAD_DATA);

                skip_whitespace(&str);
                if (*str == '\0')
                    ABORT(R_BAD_DATA);

                if ((r=grab_token(&str, &connection_address)))
                    ABORT(r);

                if (*str == '\0')
                    ABORT(R_BAD_DATA);

                addr = inet_addr(connection_address);
                if (addr == INADDR_NONE)
                    ABORT(R_BAD_DATA);

                skip_whitespace(&str);
                if (*str == '\0')
                    ABORT(R_BAD_DATA);

                if (sscanf(str, "%u", &port) != 1)
                    ABORT(R_BAD_DATA);

                if (port < 1 || port > 0x0FFFF)
                    ABORT(R_BAD_DATA);

                skip_to_past_space(&str);

#if 0
                /* TODO: !nn! just drop on the floor for now, later put somewhere */
                /* Assume v4 for now */
                if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,IPPROTO_UDP,&candidate->base))
                  ABORT(r);

                TAILQ_INSERT_TAIL(head, elm, field);
#endif

                component_id = 0;  /* prevent free */
                RFREE(connection_address);
                connection_address = 0;  /* prevent free */
            }
        }
        else if (!strncasecmp(str, "ice-lite", 8)) {
            pctx->peer_lite = 1;

            fast_forward(&str, 8);
        }
        else if (!strncasecmp(str, "ice-mismatch", 12)) {
            pctx->peer_ice_mismatch = 1;

            fast_forward(&str, 12);
        }
        else if (!strncasecmp(str, "ice-ufrag:", 10)) {
            fast_forward(&str, 10);
            if (*str == '\0')
                ABORT(R_BAD_DATA);

            skip_whitespace(&str);
            if (*str == '\0')
                ABORT(R_BAD_DATA);

            if ((r=grab_token(&str, &pctx->peer_ufrag)))
                ABORT(r);
        }
        else if (!strncasecmp(str, "ice-pwd:", 8)) {
            fast_forward(&str, 8);
            if (*str == '\0')
                ABORT(R_BAD_DATA);

            skip_whitespace(&str);
            if (*str == '\0')
                ABORT(R_BAD_DATA);

            if ((r=grab_token(&str, &pctx->peer_pwd)))
                ABORT(r);
        }
        else if (!strncasecmp(str, "ice-options:", 12)) {
            fast_forward(&str, 12);
            skip_whitespace(&str);

            while (*str != '\0') {
                if ((r=grab_token(&str, &ice_option_tag)))
                    ABORT(r);

                skip_whitespace(&str);

#if 0
//TODO: !nn! for now, just drop on the floor, later put somewhere
#endif
                ice_option_tag = 0;  /* prevent free */
            }
        }
        else {
            ABORT(R_BAD_DATA);
        }

        skip_whitespace(&str);
        /* it's expected to be at EOD at this point */

        assert(strlen(str) == 0);
    }

    _status=0;
  abort:
    if (_status) {
      if (orig)
        r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Error parsing attribute: %s",pctx->label,orig);
    }

    RFREE(connection_address);
    RFREE(component_id);
    RFREE(ice_option_tag);
    return(_status);
}
示例#8
0
int
nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_stream *stream,nr_ice_candidate **candp)
{
    int r,_status;
    char* str = orig;
    nr_ice_candidate *cand;
    char *connection_address=0;
    unsigned int port;
    in_addr_t addr;
    int i;
    unsigned int component_id;
    char *rel_addr=0;

    if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
        ABORT(R_NO_MEMORY);

    if(!(cand->label=r_strdup(orig)))
        ABORT(R_NO_MEMORY);

    cand->ctx=ctx;
    cand->isock=0;
    cand->state=NR_ICE_CAND_PEER_CANDIDATE;
    cand->stream=stream;
    skip_whitespace(&str);

    /* Candidate attr */
    if (strncasecmp(str, "candidate:", 10))
        ABORT(R_BAD_DATA);

    fast_forward(&str, 10);
    if (*str == '\0')
        ABORT(R_BAD_DATA);

    skip_whitespace(&str);
    if (*str == '\0')
        ABORT(R_BAD_DATA);

    /* Foundation */
    if ((r=grab_token(&str, &cand->foundation)))
        ABORT(r);

    if (*str == '\0')
        ABORT(R_BAD_DATA);

    skip_whitespace(&str);
    if (*str == '\0')
        ABORT(R_BAD_DATA);

    /* component */
    if (sscanf(str, "%u", &component_id) != 1)
        ABORT(R_BAD_DATA);

    if (component_id < 1 || component_id > 256)
        ABORT(R_BAD_DATA);

    cand->component_id = (UCHAR)component_id;

    skip_to_past_space(&str);
    if (*str == '\0')
        ABORT(R_BAD_DATA);

    /* Protocol */
    if (strncasecmp(str, "UDP", 3))
        ABORT(R_BAD_DATA);

    fast_forward(&str, 3);
    if (*str == '\0')
        ABORT(R_BAD_DATA);

    skip_whitespace(&str);
    if (*str == '\0')
        ABORT(R_BAD_DATA);

    /* priority */
    if (sscanf(str, "%u", &cand->priority) != 1)
        ABORT(R_BAD_DATA);

    if (cand->priority < 1)
        ABORT(R_BAD_DATA);

    skip_to_past_space(&str);
    if (*str == '\0')
        ABORT(R_BAD_DATA);

    /* Peer address/port */
    if ((r=grab_token(&str, &connection_address)))
        ABORT(r);

    if (*str == '\0')
        ABORT(R_BAD_DATA);

    addr = inet_addr(connection_address);
    if (addr == INADDR_NONE)
        ABORT(R_BAD_DATA);

    skip_whitespace(&str);
    if (*str == '\0')
        ABORT(R_BAD_DATA);

    if (sscanf(str, "%u", &port) != 1)
        ABORT(R_BAD_DATA);

    if (port < 1 || port > 0x0FFFF)
        ABORT(R_BAD_DATA);

    /* Assume v4 for now */
    if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,IPPROTO_UDP,&cand->addr))
      ABORT(r);

    skip_to_past_space(&str);
    if (*str == '\0')
        ABORT(R_BAD_DATA);

    /* Type */
    if (strncasecmp("typ", str, 3))
        ABORT(R_BAD_DATA);

    fast_forward(&str, 3);
    if (*str == '\0')
        ABORT(R_BAD_DATA);

    skip_whitespace(&str);
    if (*str == '\0')
        ABORT(R_BAD_DATA);

    assert(nr_ice_candidate_type_names[0] == 0);
    for (i = 1; nr_ice_candidate_type_names[i]; ++i) {
        if(!strncasecmp(nr_ice_candidate_type_names[i], str, strlen(nr_ice_candidate_type_names[i]))) {
            cand->type=i;
            break;
        }
    }
    if (nr_ice_candidate_type_names[i] == 0)
        ABORT(R_BAD_DATA);

    fast_forward(&str, strlen(nr_ice_candidate_type_names[i]));

    /* Look for the other side's raddr, rport */
    /* raddr, rport */
    switch (cand->type) {
    case HOST:
        break;
    case SERVER_REFLEXIVE:
    case PEER_REFLEXIVE:
    case RELAYED:

        skip_whitespace(&str);
        if (*str == '\0')
            ABORT(R_BAD_DATA);

        if (strncasecmp("raddr", str, 5))
            ABORT(R_BAD_DATA);

        fast_forward(&str, 5);
        if (*str == '\0')
            ABORT(R_BAD_DATA);

        skip_whitespace(&str);
        if (*str == '\0')
            ABORT(R_BAD_DATA);

        if ((r=grab_token(&str, &rel_addr)))
            ABORT(r);

        if (*str == '\0')
            ABORT(R_BAD_DATA);

        addr = inet_addr(rel_addr);
        if (addr == INADDR_NONE)
            ABORT(R_BAD_DATA);

        skip_whitespace(&str);
        if (*str == '\0')
            ABORT(R_BAD_DATA);

        if (strncasecmp("rport", str, 5))
              ABORT(R_BAD_DATA);

        fast_forward(&str, 5);
        if (*str == '\0')
            ABORT(R_BAD_DATA);

        skip_whitespace(&str);
        if (*str == '\0')
            ABORT(R_BAD_DATA);

        if (sscanf(str, "%u", &port) != 1)
            ABORT(R_BAD_DATA);

        if (port < 1 || port > 0x0FFFF)
            ABORT(R_BAD_DATA);

        /* Assume v4 for now */
        if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,IPPROTO_UDP,&cand->base))
          ABORT(r);

        skip_to_past_space(&str);
        /* it's expected to be at EOD at this point */

        break;
    default:
        ABORT(R_INTERNAL);
        break;
    }

    skip_whitespace(&str);

    assert(strlen(str) == 0);

    *candp=cand;

    _status=0;
  abort:
    if (_status)
        r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Error parsing attribute: %s",ctx->label,orig);

    RFREE(connection_address);
    RFREE(rel_addr);
    return(_status);
}
示例#9
0
/*
 * _bitmap_union() -- union 'numBatches' bitmaps
 *
 * All bitmap words are HRL compressed. The result bitmap words are also
 * HRL compressed, except that fill unset words may be lossily compressed.
 */
void
_bitmap_union(BMBatchWords **batches, uint32 numBatches, BMBatchWords *result)
{
	bool 		done = false;
	uint32 	   *prevstarts;
	uint64		nextReadNo;
	uint64		batchNo;

	Assert ((int)numBatches >= 0);

	if (numBatches == 0)
		return;

	/* save batch->startNo for each input bitmap vector */
	prevstarts = (uint32 *)palloc0(numBatches * sizeof(uint32));

	/* 
	 * Compute the next read offset. We fast forward compressed
	 * zero words when possible.
	 */
	nextReadNo = fast_forward(numBatches, batches, result);

	while (!done &&	result->nwords < result->maxNumOfWords)
	{
		BM_HRL_WORD orWord = LITERAL_ALL_ZERO;
		BM_HRL_WORD	word;
		bool		orWordIsLiteral = true;

		for (batchNo = 0; batchNo < numBatches; batchNo++)
		{
			BMBatchWords *bch = batches[batchNo];

			/* skip nextReadNo - nwordsread - 1 words */
			_bitmap_findnextword(bch, nextReadNo);

			if (bch->nwords == 0)
			{
				done = true;
				break;
			}

			Assert(bch->nwordsread == nextReadNo - 1);

			/* Here, startNo should point to the word to be read. */
			word = bch->cwords[bch->startNo];

			if (CUR_WORD_IS_FILL(bch) && GET_FILL_BIT(word) == 1)
			{
				/* Fill word represents matches */
				bch->nwordsread += FILL_LENGTH(word);
				orWord = BM_MAKE_FILL_WORD(1, bch->nwordsread - nextReadNo + 1);
				orWordIsLiteral = false;

				nextReadNo = bch->nwordsread + 1;
				bch->startNo++;
				bch->nwords--;
				break;
			}
			else if (CUR_WORD_IS_FILL(bch) && GET_FILL_BIT(word) == 0)
			{
				/* Fill word represents no matches */

				bch->nwordsread++;
				prevstarts[batchNo] = bch->startNo;
				if (FILL_LENGTH(word) == 1)
				{
					bch->startNo++;
					bch->nwords--;
				}
				else
					bch->cwords[bch->startNo]--;
				orWordIsLiteral = true;
			}
			else if (!CUR_WORD_IS_FILL(bch))
			{
				/* word is literal */
				prevstarts[batchNo] = bch->startNo;
				orWord |= word;
				bch->nwordsread++;
				bch->startNo++;
				bch->nwords--;
				orWordIsLiteral = true;
			}
		}

		if (done)
		{
			uint32 i;

			/* reset the attributes before batchNo */
			for (i = 0; i < batchNo; i++)
				_bitmap_resetWord(batches[i], prevstarts[i]);
			break;
		}
		else
		{
			if (!orWordIsLiteral)
			{
				 /* Word is not literal, update the result header */
				uint32 	offs = result->nwords/BM_HRL_WORD_SIZE;
				uint32	n = result->nwords;
				result->hwords[offs] |= WORDNO_GET_HEADER_BIT(n);
			}
			result->cwords[result->nwords] = orWord;
			result->nwords++;
		}

		if (orWordIsLiteral)
			nextReadNo++;

		/* we just processed the last batch and it was empty */
		if (batchNo == numBatches - 1 && batches[batchNo]->nwords == 0)
			done = true;
	}

	/* set the next word to read for all input vectors */
	for (batchNo = 0; batchNo < numBatches; batchNo++)
		batches[batchNo]->nextread = nextReadNo;

	pfree(prevstarts);
}
示例#10
0
int main(int argc, char *argv[])
{
  char          inkey=0, *prgdir, *curdir, *program_name;
  bool          ext, validcfg, quit = false, bkgply = false, batchply = false;
  unsigned int	opt, prgdrive, i;
  CWindow       *focus;

#ifdef DEBUG
  f_log = fopen(DEBUG_FILE,"wt");
#endif

  std::cout << ADPLAYVERS << ", Copyright (c) 2000 - 2006 Simon Peter <*****@*****.**>" << std::endl << std::endl;

  // check that no other instance is running
  {
    char *adplayenv = getenv("ADPLAY");

    if(adplayenv && !strcmp(adplayenv,"S")) {
      std::cout << "AdPlay already running!" << std::endl;
      exit(EXIT_FAILURE);
    } else
      setenv("ADPLAY","S",1); // flag our instance
  }

  // Build program executable name
  program_name = strrchr(argv[0], '\\') ? strrchr(argv[0], '\\') + 1 : argv[0];

  CAdPlug::debug_output("debug.log"); // Redirect AdPlug's debug to file
  // Build path to default configuration file (in program's directory)
  SPLITPATH(argv[0],configfile,configfile+2,NULL,NULL);
  strcat(configfile,CONFIGFILE);

  loadconfig(configfile,DEFCONFIG);       // load default configuration

  // parse commandline for general options
  while((opt = getopt(argc,argv)))
    switch(opt) {
    case 1:	// display help
    case 2:
      std::cout << "Usage: " << program_name << " [options]" << std::endl << std::endl;
      std::cout << "Options can be set with '-' or '/' respectively." << std::endl << std::endl;
      std::cout << " -?, -h      Display commandline help" << std::endl <<
	" -p port     Set OPL2 port" << std::endl <<
	" -o          Force OPL2 port" << std::endl <<
	" -f file     Use alternate configuration file" << std::endl <<
	" -c section  Load another configuration section" << std::endl <<
	" -b file     Immediate background playback using " <<
	"specified file" << std::endl <<
	" -q files    Immediate (batch mode) playback using " <<
	"specified files" << std::endl;
      showcursor();
      exit(EXIT_SUCCESS);
    case 3:	// set OPL2 port
      opl.setport(atoi(argv[myoptind++]));
      break;
    case 4: // force OPL2 port
      oplforce = true;
      break;
    case 7:	// background playback
      bkgply = true;
      break;
    case 8: // batch mode playback
      batchply = true;
      break;
    }

  // Bail out if OPL2 not detected and not force
  if(!opl.detect() && !oplforce) {
    std::cout << "No OPL2 detected!" << std::endl;
    showcursor();
    exit(EXIT_FAILURE);
  }

  // Hand our database to AdPlug
  CAdPlug::set_database(&mydb);

  /*** Background playback mode ***/
  if(bkgply)
    if(!(p = CAdPlug::factory(argv[myoptind],&opl))) {
      std::cout << "[" << argv[myoptind] << "]: unsupported file type!" << std::endl;
      exit(EXIT_FAILURE);
    } else {
      std::cout << "Background playback... (type EXIT to stop)" << std::endl;
#ifdef HAVE_WCC_TIMER_H
      tmInit(poll_player,0xffff,DEFSTACK);
#elif defined HAVE_GCC_TIMER_H
      timer_init(poll_player);
#endif
      dopoll = true;
#ifdef __WATCOMC__
      _heapshrink();
#endif
      system(getenv("COMSPEC"));
#ifdef HAVE_WCC_TIMER_H
      tmClose();
#elif defined HAVE_GCC_TIMER_H
      timer_deinit();
#endif
      stop();
      exit(EXIT_SUCCESS);
    }

  /*** Batch playback mode ***/
  if(batchply) {
#ifdef HAVE_WCC_TIMER_H
    tmInit(poll_player,0xffff,DEFSTACK);
#elif defined HAVE_GCC_TIMER_H
    timer_init(poll_player);
#endif

    for(i = myoptind; i < argc; i++)
      if(!(p = CAdPlug::factory(argv[i],&opl))) {
	std::cout << "[" << argv[i] << "]: unsupported file type!" << std::endl;
#ifdef HAVE_WCC_TIMER_H
	tmClose();
#elif defined HAVE_GCC_TIMER_H
	timer_deinit();
#endif
	exit(EXIT_FAILURE);
      } else {
	dopoll = firsttime = true;
	std::cout << "Playing [" << argv[i] << "] ..." << std::endl;
	while(firsttime) ;	// busy waiting
	stop();
	dopoll = false;
      }

#ifdef HAVE_WCC_TIMER_H
    tmClose();
#elif defined HAVE_GCC_TIMER_H
    timer_deinit();
#endif
    exit(EXIT_SUCCESS);
  }

  /*** interactive (GUI) mode ***/
  getvideoinfo(&dosvideo);        // Save previous video state

  // register our windows with the window manager
  wnds.reg(titlebar); wnds.reg(filesel); wnds.reg(songwnd);
  wnds.reg(instwnd); wnds.reg(volbars); wnds.reg(mastervol);
  wnds.reg(infownd);

  // load default GUI layout
  validcfg = loadcolors(configfile,DEFCONFIG);

  // reparse commandline for GUI options
  myoptind = 1;     // reset option parser
  while((opt = getopt(argc,argv)))
    switch(opt) {
    case 5:	// set config file
      strcpy(configfile,argv[myoptind++]);
      if(loadcolors(configfile,DEFCONFIG))
	validcfg = true;
      break;
    case 6:	// load config section
      loadcolors(configfile,argv[myoptind++]);
      break;
    }

  // bail out if no configfile could be loaded
  if(!validcfg) {
    std::cout << "No valid default GUI layout could be loaded!" << std::endl;
    exit(EXIT_FAILURE);
  }

  // init GUI
  if((tmpfn = TEMPNAM(getenv("TEMP"),"_AP")))
#ifdef __WATCOMC__
    mkdir(tmpfn);
#else
  mkdir(tmpfn, S_IWUSR);
#endif
  prgdir = getcwd(NULL, PATH_MAX); _dos_getdrive(&prgdrive);
  setadplugvideo();
#ifdef HAVE_WCC_TIMER_H
  tmInit(poll_player,0xffff,DEFSTACK);
#elif defined HAVE_GCC_TIMER_H
  timer_init(poll_player);
#endif
  songwnd.setcaption("Song Info"); volbars.setcaption("VBars");
  titlebar.setcaption(ADPLAYVERS); filesel.setcaption("Directory");
  mastervol.setcaption("Vol"); filesel.refresh(); mastervol.set(63);
  display_help(infownd); filesel.setfocus(); reset_windows();

  // main loop
  do {
    if(p) {	// auto-update windows
      //                        wait_retrace();
      idle_ms(1000/70);
      refresh_songinfo(songwnd);
      refresh_volbars(volbars,opl);

      if(onsongend && !firsttime) {	// song ended
	switch(onsongend) {
	case 1:	// auto-rewind
	  dopoll = false; while(inpoll) ;	// critical section...
	  p->rewind(subsong);
	  last_ms = time_ms = 0.0f;
	  dopoll = true;	// ...End critical section
	  break;
	case 2:	// stop playback
	  stop();
	  reset_windows();
	  break;
	}
      }
    }

    // Check for keypress and read in, if any
    if(kbhit()) {
      if(!(inkey = toupper(getch()))) {
	ext = true;
	inkey = toupper(getch());
      } else
	ext = false;

      focus = CWindow::getfocus(); // cache focused window
      dbg_printf("main(): Key pressed: %d %s\n",
		 inkey, ext ? "(Ext)" : "(Norm)");
    } else
      inkey = 0;

    if(ext)	// handle all extended keys
      switch(inkey) {
      case 15:        // [Shift]+[TAB] - Back cycle windows
	window_cycle(true);
	break;
      case 59:	// [F1] - display help
	display_help(infownd);
	infownd.setfocus();
	wnds.update();
	break;
      case 60:	// [F2] - change screen layout
	curdir = getcwd(NULL, PATH_MAX);
	chdir(prgdir);
	select_colors();
	chdir(curdir);
	free(curdir);
	clearscreen(backcol);
	filesel.refresh();
	wnds.update();
	break;
      case 72:        // [Up Arrow] - scroll up
	if(focus == &filesel) {
	  filesel.select_prev();
	  filesel.update();
	} else if(focus == &infownd) {
	  infownd.scroll_up();
	  infownd.update();
	} else if(focus == &instwnd) {
	  instwnd.scroll_up();
	  instwnd.update();
	}
	break;
      case 80:        // [Down Arrow] - scroll down
	if(focus == &filesel) {
	  filesel.select_next();
	  filesel.update();
	} else if(focus == &infownd) {
	  infownd.scroll_down();
	  infownd.update();
	} else if(focus == &instwnd) {
	  instwnd.scroll_down();
	  instwnd.update();
	}
	break;
      case 75:	// [Left Arrow] - previous subsong
	if(p && subsong) {
	  subsong--;
	  dopoll = false; while(inpoll) ;	// critical section...
	  totaltime = p->songlength(subsong);
	  p->rewind(subsong);
	  last_ms = time_ms = 0.0f;
	  dopoll = true;	// ...End critical section
	}
	break;
      case 77:	// [Right Arrow] - next subsong
	if(p && subsong < p->getsubsongs()-1) {
	  subsong++;
	  dopoll = false; while(inpoll) ;	// critical section...
	  totaltime = p->songlength(subsong);
	  p->rewind(subsong);
	  last_ms = time_ms = 0.0f;
	  dopoll = true;	// ...End critical section
	}
	break;
      case 73:        // [Page Up] - scroll up half window
	if(focus == &filesel) {
	  filesel.select_prev(filesel.getsizey() / 2);
	  filesel.update();
	} else if(focus == &infownd) {
	  infownd.scroll_up(infownd.getsizey() / 2);
	  infownd.update();
	} else if(focus == &instwnd) {
	  instwnd.scroll_up(instwnd.getsizey() / 2);
	  instwnd.update();
	}
	break;
      case 81:        // [Page Down] - scroll down half window
	if(focus == &filesel) {
	  filesel.select_next(filesel.getsizey() / 2);
	  filesel.update();
	} else if(focus == &infownd) {
	  infownd.scroll_down(infownd.getsizey() / 2);
	  infownd.update();
	} else if(focus == &instwnd) {
	  instwnd.scroll_down(instwnd.getsizey() / 2);
	  instwnd.update();
	}
	break;
      case 71:        // [Home] - scroll to start
	if(focus == &filesel) {
	  filesel.setselection(0);
	  filesel.update();
	} else if(focus == &infownd) {
	  infownd.scroll_set(0);
	  infownd.update();
	} else if(focus == &instwnd) {
	  instwnd.scroll_set(0);
	  instwnd.update();
	}
	break;
      case 79:        // [End] - scroll to end
	if(focus == &filesel) {
	  filesel.setselection(0xffff);
	  filesel.update();
	} else if(focus == &infownd) {
	  infownd.scroll_set(0xffff);
	  infownd.update();
	} else if(focus == &instwnd) {
	  instwnd.scroll_set(0xffff);
	  instwnd.update();
	}
	break;
      }
    else		// handle all normal keys
      switch(inkey) {
      case 9:         // [TAB] - Cycle through windows
	window_cycle();
	break;
      case 13:        // [Return] - Activate
	if(focus == &filesel)
	  activate();
	break;
      case 27:        // [ESC] - Stop music / Exit to DOS
	if(p) {
	  stop();
	  reset_windows();
	} else
	  quit = true;
	break;
      case ' ':	// [Space] - fast forward
	fast_forward(FF_MSEC);
	break;
      case 'M':	// refresh song info
	refresh_songdesc(infownd);
	break;
      case 'D':	// shell to DOS
	dosshell(getenv("COMSPEC"));
	filesel.refresh(); wnds.update();
	break;
      case '+':       // [+] - Increase volume
	adjust_volume(-1);
	break;
      case '-':       // [-] - Decrease volume
	adjust_volume(+1);
	break;
      }
  } while(!quit);

  // deinit
#ifdef HAVE_WCC_TIMER_H
    tmClose();
#elif defined HAVE_GCC_TIMER_H
    timer_deinit();
#endif
  stop();
  setvideoinfo(&dosvideo);
  {
    unsigned int dummy;
    _dos_setdrive(prgdrive, &dummy);
  }
  chdir(prgdir);
  free(prgdir);
  if(tmpfn) { rmdir(tmpfn); free(tmpfn); }
#ifdef DEBUG
  dbg_printf("main(): clean shutdown.\n");
  fclose(f_log);
#endif
  return EXIT_SUCCESS;
}