void init(size_type (*pfn)(char_type*, size_type))
    {
        // We don't pass NULL here, just in case
        char_type empty =   '\0';
        size_type cch   =   pfn(&empty, 0);

        if(m_buffer.resize(1 + cch))
        {
            for(;;)
            {
                cch = pfn(&m_buffer[0], m_buffer.size());

                if(cch < m_buffer.size())
                {
                    m_len = cch;
                    break;
                }
                else
                {
                    if(!m_buffer.resize(2 * m_buffer.size()))
                    {
                        m_buffer.resize(0);
                        break;
                    }
                }
            }
        }

        m_buffer[m_len] = '\0';
    }
inline 
double RunTestImpl ( const char* title, void (*pfn)(), char* histogramFileName = no_histogram ) {
    double  time = 0, variation = 0, deviation = 0;
    size_t nrep = 1;
    while (true) {
        CalibrateTiming(NRUNS, 1, nrep);
        StartTiming(NRUNS, 1, nrep);
        pfn();
        StopTiming(time, variation, deviation);
        time -= util::base;
        if ( time > 1e-6 )
            break;
        nrep *= 2;
    }
    nrep *= (size_t)ceil(ONE_TEST_DURATION/time);
    CalibrateTiming(NRUNS, 1, nrep);    // sets util::base
    util::durations_t  t;
    StartTimingEx(t, NRUNS, 1, nrep);
        pfn();
    StopTiming(time, variation, deviation);
    if ( histogramFileName != (char*)-1 )
        util::trace_histogram(t, histogramFileName);
    double clean_time = time - util::base;
    if ( title ) {
        // Deviation (in percent) is calulated for the Gross time
        printf ("\n%-34s %.2e  %5.1f      ", title, clean_time, deviation);
        if ( util::sequential_time != 0  )
            //printf ("% .2e  ", clean_time - util::sequential_time);
            printf ("% 10.1f      ", 100*(clean_time - util::sequential_time)/util::sequential_time);
        else
            printf ("%*s ", util::rate_field_len, "");
        printf ("%-9u %1.6f    |", (unsigned)nrep, time * nrep);
    }
    return clean_time;
}
    void init(argument_0_type arg0, size_type (*pfn)(argument_0_type, char_type*, size_type))
    {
        size_type cch = pfn(arg0, NULL, 0);   // We don't pass NULL here, just in case

        if(m_buffer.resize(1 + cch))
        {
            for(;;)
            {
                cch = pfn(arg0, &m_buffer[0], m_buffer.size());

                if(cch < m_buffer.size())
                {
                    m_len = cch;
                    break;
                }
                else
                {
                    if(!m_buffer.resize(2 * m_buffer.size()))
                    {
                        m_buffer.resize(0);
                        break;
                    }
                }
            }
        }

        m_buffer[m_len] = '\0';
    }
Exemplo n.º 4
0
	void Hash::forEach(void (*pfn)(Object*, Object*, void*), void* userdata){
		if(!pfn) return;
		HashIterator* it =dynamic_cast<HashIterator*>(iterator());
		while(it->next()){
			pfn(it->getKey(), it->getValue(), userdata);
		}
	}
Exemplo n.º 5
0
void        DrvMountDrivesThread( void * hev)

{
    ULONG       rc;
    HMODULE     hmod = 0;
    pRediscover_PRMs    pfn = 0;
    char *      pErr = 0;
    char        szErr[16];

    rc = DosLoadModule( szErr, sizeof(szErr), "LVM", &hmod);
    if (rc)
        pErr = "DosLoadModule";
    else {
        rc = DosQueryProcAddr( hmod, 0, "Rediscover_PRMs", (PFN*)&pfn);
        if (rc)
            pErr = "DosQueryProcAddr";
        else {
            pfn( &rc);
            if (rc)
                pErr = "Rediscover_PRMs";
        }
        rc = DosFreeModule( hmod);
        if (rc && !pErr)
            pErr = "DosFreeModule";
    }

    if (pErr)
        printf( "DrvMountDrivesThread - %s - rc= %lx\n", pErr, rc);

    rc = DosPostEventSem( (HEV)hev);
    if (rc)
        printf( "DrvMountDrivesThread - DosPostEventSem - rc= %lx\n", rc);

    return;
}
Exemplo n.º 6
0
void CAVPlayer::OnVLC_Event( const libvlc_event_t *event, void *data )
{
    CAVPlayer *pAVPlayer = (CAVPlayer *) data;
    pfnCallback pfn = NULL;

    if (! pAVPlayer)
    {
        return;
    }

    switch(event->type)
    {
    case libvlc_MediaPlayerPlaying:
        pfn = pAVPlayer->m_pfnPlaying;
        break;
    case libvlc_MediaPlayerPositionChanged:
        pfn = pAVPlayer->m_pfnPosChanged;
        break;
    case libvlc_MediaPlayerEndReached:
        pfn = pAVPlayer->m_pfnEndReached;
        break;
    default:
        break;
    }
//	libvlc_media_player_get_state
    if (pfn)
    {
        pfn(data);  // 此回调函数还可以传入其他参数,除了data外,还有event的各种信息(如event->u.media_player_position_changed.new_position)等等,请自行扩展。
    }   
}
Exemplo n.º 7
0
Arquivo: proc.c Projeto: Sunmonds/gcc
// Called to start an M.
void*
runtime_mstart(void* mp)
{
	m = (M*)mp;
	g = m->g0;

	g->entry = nil;
	g->param = nil;

	// Record top of stack for use by mcall.
	// Once we call schedule we're never coming back,
	// so other calls can reuse this stack space.
#ifdef USING_SPLIT_STACK
	__splitstack_getcontext(&g->stack_context[0]);
#else
	g->gcinitial_sp = &mp;
	g->gcstack_size = StackMin;
	g->gcnext_sp = &mp;
#endif
	getcontext(&g->context);

	if(g->entry != nil) {
		// Got here from mcall.
		void (*pfn)(G*) = (void (*)(G*))g->entry;
		G* gp = (G*)g->param;
		pfn(gp);
		*(int*)0x21 = 0x21;
	}
	runtime_minit();
	schedule(nil);
	return nil;
}
Exemplo n.º 8
0
Actor* ActorUtil::LoadFromNode( const XNode* pNode, Actor *pParentActor )
{
	ASSERT( pNode );

	/* TODO: Remove this in favor of using conditionals in Lua. */
	{
		bool bCond;
		if( pNode->GetAttrValue("Condition", bCond) && !bCond )
			return NULL;
	}

	RString sClass;
	pNode->GetAttrValue( "Class", sClass );

	map<RString,CreateActorFn>::iterator iter = g_pmapRegistrees->find( sClass );
	if( iter == g_pmapRegistrees->end() )
	{
		// sClass is invalid
		RString sError = ssprintf( "%s: invalid Class \"%s\"",
			ActorUtil::GetWhere(pNode).c_str(), sClass.c_str() );
		Dialog::OK( sError );
		return new Actor;	// Return a dummy object so that we don't crash in AutoActor later.
	}

	const CreateActorFn &pfn = iter->second;
	Actor *pRet = pfn();

	if( pParentActor )
		pRet->SetParent( pParentActor );

	pRet->LoadFromNode( pNode );
	return pRet;
}
Exemplo n.º 9
0
SECURITY_ATTRIBUTES* XAccessControl::getHighPrivSA()
{
	static SECURITY_ATTRIBUTES gsHighSA;

	if (!mbSecSAInit)
	{
		gsHighSA.nLength = sizeof(SECURITY_ATTRIBUTES);
		gsHighSA.bInheritHandle = FALSE;

		/*
		The format is a null-terminated string with tokens to indicate each of the four main components of a security
		descriptor: owner (0:), primary group (G:), DACL (D:), and SACL (S:)
		*/

		wchar_t* wszSD = L"D:"		// Discretionary ACL
			L"(A;OICI;GAFA;;;BA)"	// Allow full control to administrators
			L"(A;OICI;GAFA;;;SY)";	// Allow full control to SYSTEM

		fn_ConvertStringSecurityDescriptorToSecurityDescriptorW* pfn = GetSecurityFuncAddress();

		if (pfn)
		{
			mbSecSAInit = pfn(wszSD, SDDL_REVISION_1, &gsHighSA.lpSecurityDescriptor, NULL);
		}
		else
		{
			gsHighSA.lpSecurityDescriptor = NULL;
		}
	}
	return &gsHighSA;
}
Exemplo n.º 10
0
unsigned int random_int() {
    unsigned int n;
#if defined(_WIN32)
#if defined(__CYGWIN32__)
    HMODULE hLib=LoadLibrary((const char *)"ADVAPI32.DLL");
#else
    HMODULE hLib=LoadLibrary("ADVAPI32.DLL");
#endif
    if (!hLib) {
        die("Can't load ADVAPI32.DLL");
    }
    BOOLEAN (APIENTRY *pfn)(void*, ULONG) =
    (BOOLEAN (APIENTRY *)(void*,ULONG))GetProcAddress(hLib,"SystemFunction036");
    if (pfn) {
        char buff[32];
        ULONG ulCbBuff = sizeof(buff);
        if(pfn(buff,ulCbBuff)) {
            // use buff full of random goop
            memcpy(&n,buff,sizeof(n));
        }
    }
    FreeLibrary(hLib);
#else
    FILE* f = fopen("/dev/random", "r");
    if (!f) {
        die("can't open /dev/random\n");
    }
    fread(&n, sizeof(n), 1, f);
#endif
    return n;
}
Exemplo n.º 11
0
SECURITY_ATTRIBUTES* XAccessControl::getLowPrivSA()
{
	static SECURITY_ATTRIBUTES gsLowSA;

	if (!mbSecLowSAInit)
	{
		gsLowSA.nLength = sizeof(SECURITY_ATTRIBUTES);
		gsLowSA.bInheritHandle = FALSE;

		/* Example
		TCHAR* szSD = TEXT("D:") // Discretionary ACL
			TEXT("(D;OICI;GA;;;BG)")	// Deny access to built-in guests
			TEXT("(D;OICI;GA;;;AN)")	// Deny access to anonymous logon
			TEXT("(A;OICI;GRGWGX;;;AU)")	// Allow read/write/execute to authenticated users
			TEXT("(A;OICI;GA;;;BA)");		// Allow full control to administrators
		*/

		wchar_t* wszSD = L"O:"	// Discretionary ACL
			L"(A;OICI;GAFA;;;BA)"	// allow full control to administrators
			L"(A;OICI;GAFA;;;SY)";	// Allow full control to SYSTEM

		fn_ConvertStringSecurityDescriptorToSecurityDescriptorW* pfn = GetSecurityFuncAddress(); // 함수 포인터를 가져온다.

		if (pfn)
		{
			mbSecLowSAInit = pfn(wszSD, SDDL_REVISION_1, &gsLowSA.lpSecurityDescriptor, NULL);
		}
		else
		{
			gsLowSA.lpSecurityDescriptor = NULL;
		}
	}
	return &gsLowSA;
}
static PyObject *
pf_create(PyObject *self, PyObject *args)
{
    struct pfHandle *pfh = (pfHandle *)malloc(sizeof(struct pfHandle));
    void *dlHandle;
    PyObject *pyobj;
    pf_obj *(*pfn)(void); 
    if(!PyArg_ParseTuple(args,"O",&pyobj))
    {
	return NULL;
    }
    if(!PyCObject_Check(pyobj))
    {
	PyErr_SetString(PyExc_ValueError,"Not a valid handle");
	return NULL;
    }

    dlHandle = PyCObject_AsVoidPtr(pyobj);
    pfn = (pf_obj *(*)(void))dlsym(dlHandle,"pf_new");
    if(NULL == pfn)
    {
	PyErr_SetString(PyExc_ValueError,dlerror());
	return NULL;
    }
    pf_obj *p = pfn();
    pfh->pfo = p;
    pfh->pyhandle = pyobj;
#ifdef DEBUG_CREATION
    printf("%p : PF : CTOR (%p)\n",pfh,pfh->pfo);
#endif
    // refcount module so it can't be unloaded before all funcs are gone
    Py_INCREF(pyobj); 
    return PyCObject_FromVoidPtr(pfh,pf_delete);
}
DWORD GetShell32Version ()
{
	
	static DWORD dwVer = 0;

	if (dwVer == 0)
	{
		HMODULE hLib = LoadLibrary ("shell32.dll");
		if (hLib == NULL)
			return 0;

		fntDllGetVersion pfn = (fntDllGetVersion) GetProcAddress (hLib, "DllGetVersion");

		if (pfn == NULL)
		{
			FreeLibrary (hLib);
			return 0;
		}

		DLLVERSIONINFO info;
		info.cbSize = sizeof (info);
		pfn (&info);

		FreeLibrary (hLib);

		return dwVer = info.dwMajorVersion;
	}

	return dwVer;
}
Exemplo n.º 14
0
Arquivo: rbt.c Projeto: liuyanfu/cliui
RBT_NODE_S* RBT_SearchAux(key_type key, RBT_NODE_S* pstRoot, RBT_NODE_S** save, pfnDataCmp pfn)
{
    RBT_NODE_S *pstNode = pstRoot, *pstParent = NULL;
    int iRet = 0;

    while (pstNode)
    {
        pstParent = pstNode;
        iRet = pfn(pstNode->key, key);
        if (0 < iRet)
        {
            pstNode = pstNode->pstLeft;
        }
        else if (0 > iRet)
        {
            pstNode = pstNode->pstRight;
        }
        else
        {
            return pstNode;
        }
    }

    if (save)
    {
        *save = pstParent;
    }

    return NULL;
}
Exemplo n.º 15
0
Arquivo: rbt.c Projeto: liuyanfu/cliui
RBT_NODE_S* RBT_Insert(key_type key, data_t data, RBT_NODE_S* pstRoot, pfnDataCmp pfn)
{
    RBT_NODE_S *pstParent = NULL;
    RBT_NODE_S *pstNode = NULL;

    pstParent = NULL;
    if ((pstNode = RBT_SearchAux(key, pstRoot, &pstParent, pfn)))
    {
        return pstRoot;
    }

    pstNode = RBT_NewNode(key, data);
    pstNode->pstParent = pstParent; 
    pstNode->pstLeft = pstNode->pstRight = NULL;
    pstNode->enColor = RED;

    if (pstParent)
    {
        if (pfn(pstParent->key, key) > 0) //pstParent->key > key)
        {
            pstParent->pstLeft = pstNode;
        }
        else
        {
            pstParent->pstRight = pstNode;
        }
    }
    else
    {
        pstRoot = pstNode;
    }

    return RBT_InsertRebalance(pstNode, pstRoot);
}
Exemplo n.º 16
0
Value BuiltinFunc::call(Value self, Value member, short nargs, short nargnames,
	short* argnames, int each) {
	if (member != CALL)
		return Func::call(self, member, nargs, nargnames, argnames, each);
	args(nargs, nargnames, argnames, each);
	Framer frame(this, self);
	return pfn();
}
Exemplo n.º 17
0
	void Hash::removeIf(bool (*pfn)(Object*, Object*)){
		if(!pfn) return;
		HashIterator* it =dynamic_cast<HashIterator*>(iterator());
		while(it->next()){
			if(pfn(it->getKey(), it->getValue())){
				it->remove();
			}
		}
	}
Exemplo n.º 18
0
String Path::GetTruePath(RCString p) {
#if UCFG_USE_POSIX	
	char buf[PATH_MAX];
	for (const char *psz = p;; psz = buf) {
		int len = ::readlink(psz, buf, sizeof(buf)-1);
		if (len == -1) {
			if (errno == EINVAL)
				return psz;
			CCheck(-1);
		}
		buf[len] = 0;
	}
#elif UCFG_WIN32_FULL
	TCHAR buf[_MAX_PATH];
	DWORD len = ::GetLongPathName(p, buf, _countof(buf)-1);
	Win32Check(len != 0);
	buf[len] = 0;

	typedef DWORD (WINAPI *PFN_GetFinalPathNameByHandle)(HANDLE hFile, LPTSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags);

	DlProcWrap<PFN_GetFinalPathNameByHandle> pfn("KERNEL32.DLL", EXT_WINAPI_WA_NAME(GetFinalPathNameByHandle));
	if (!pfn)
		return buf;
	TCHAR buf2[_MAX_PATH];
	File file;
	file.Attach(::CreateFile(buf, 0, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
	len = pfn(Handle(file), buf2, _countof(buf2)-1, 0);
	Win32Check(len != 0);
	buf2[len] = 0;	
#if UCFG_USE_REGEX
	wcmatch m;
	if (regex_search(buf2, m, s_reDosName))
		return m[1];
#else
	String sbuf(buf2);				//!!! incoplete check, better to use Regex
	int idx = sbuf.Find(':');
	if (idx != -1)
		return sbuf.Mid(idx-1);
#endif
	return buf2;
#else
	return p;
#endif
}
Exemplo n.º 19
0
/*
 * Platform-independent function to get the event configuration for LL.
 */
void
plat_ll_config(plat_event_config_t *cfg)
{
	pfn_plat_ll_config_t pfn =
	    s_plat_ll_config[s_cpu_type];

	if (pfn != NULL) {
		pfn(cfg);
	}
}
Exemplo n.º 20
0
static int __IsPackagedAppHelper(void)
{
    LONG retValue = APPMODEL_ERROR_NO_PACKAGE;
    UINT32 bufferLength = 0;

#if defined (_M_IX86) || defined (_M_X64)
    IFDYNAMICGETCACHEDFUNCTION(KERNEL32, PFN_GetCurrentPackageId, GetCurrentPackageId, pfn) \
    {
        retValue = pfn(&bufferLength, NULL);
    }
Exemplo n.º 21
0
/*
 * Platform-independent function to get the event configuration for profiling.
 */
void
plat_profiling_config(count_id_t count_id, plat_event_config_t *cfg)
{
	pfn_plat_profiling_config_t pfn =
	    s_plat_profiling_config[s_cpu_type];

	if (pfn != NULL) {
		pfn(count_id, cfg);
	}
}
Exemplo n.º 22
0
/** Invokes a front-end process-identity function, implementating all the
 * exception-handling boilerplate for the function.
 *
 * \param pfn The front-end process-identity function
 * \param token The <code>token</code> parameter to be passed to <code>pfn</code>
 * \param feName A human-readable name that identifies the front-end, used in
 *   bail-out calls in severe/fatal conditions
 */
PANTHEIOS_CALL(PAN_CHAR_T const*) pantheios_call_fe_getProcessIdentity(
    pantheios_fe_X_getProcessIdentity_pfn_t pfn
,   void*                                   token
,   char const*                             feName
);
#else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
inline
PAN_CHAR_T const*
pantheios_call_fe_getProcessIdentity(
    pantheios_fe_X_getProcessIdentity_pfn_t pfn
,   void*                                   token
,   char const*                             /* feName */
)
{
    return pfn(token);
}
static void thread_timer_func(void *cxt)
{
   VCOS_THREAD_T *self = (VCOS_THREAD_T *)cxt;
   void (*pfn)(void*) = self->_timer.pfn;

   vcos_assert(self);
   vcos_assert(self->magic == VCOS_THREAD_MAGIC);
   vcos_assert(self->_timer.pfn);
   self->_timer.pfn = NULL;
   pfn(self->_timer.cxt);
}
Exemplo n.º 24
0
void task_run(void) {
	for(int i = 0; i < 32; i++) {
		if(!tasks[i].pfn)
			// No further tasks to be run
			return;
		
		// Clear the task, we have executed it
		void (*pfn)(void*, void*) = tasks[i].pfn;
		tasks[i].pfn = NULL;
		pfn(tasks[i].pContext1, tasks[i].pContext2);
	}
}
Exemplo n.º 25
0
/*
 * Platform-independent function to return the number of offcore counters.
 */
int
plat_offcore_num(void)
{
	pfn_plat_offcore_num_t pfn =
	    s_plat_offcore_num[s_cpu_type];

	if (pfn != NULL) {
		return (pfn());
	}
	
	return (0);
}
Exemplo n.º 26
0
static int OGRSQLiteVFSOpen(sqlite3_vfs* pVFS,
                            const char *zName,
                            sqlite3_file* pFile,
                            int flags,
                            int *pOutFlags)
{
#ifdef DEBUG_IO
    CPLDebug("SQLITE", "OGRSQLiteVFSOpen(%s, %d)", zName ? zName : "(null)", flags);
#endif

    OGRSQLiteVFSAppDataStruct* pAppData = (OGRSQLiteVFSAppDataStruct* )pVFS->pAppData;

    if (zName == NULL)
    {
        zName = CPLSPrintf("/vsimem/sqlite/%p_%d",
                           pVFS, CPLAtomicInc(&(pAppData->nCounter)));
    }

    OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
    pMyFile->pMethods = NULL;
    pMyFile->bDeleteOnClose = FALSE;
    pMyFile->pszFilename = NULL;
    if ( flags & SQLITE_OPEN_READONLY )
        pMyFile->fp = VSIFOpenL(zName, "rb");
    else if ( flags & SQLITE_OPEN_CREATE )
        pMyFile->fp = VSIFOpenL(zName, "wb+");
    else if ( flags & SQLITE_OPEN_READWRITE )
        pMyFile->fp = VSIFOpenL(zName, "rb+");
    else
        pMyFile->fp = NULL;

    if (pMyFile->fp == NULL)
        return SQLITE_CANTOPEN;

#ifdef DEBUG_IO
    CPLDebug("SQLITE", "OGRSQLiteVFSOpen() = %p", pMyFile->fp);
#endif

    pfnNotifyFileOpenedType pfn = pAppData->pfn;
    if (pfn)
    {
        pfn(pAppData->pfnUserData, zName, pMyFile->fp);
    }

    pMyFile->pMethods = &OGRSQLiteIOMethods;
    pMyFile->bDeleteOnClose = ( flags & SQLITE_OPEN_DELETEONCLOSE );
    pMyFile->pszFilename = CPLStrdup(zName);

    if (pOutFlags != NULL)
        *pOutFlags = flags;

    return SQLITE_OK;
}
Exemplo n.º 27
0
   pfnType CLibrary::Resolve( const std::string& anEntry )const
   {
      TRACE_FUN( Frequently, "CLibrary::resolve" );

      pfnType pfn( 0 );

      if( IsLoaded() )
      {
         pfn = reinterpret_cast< pfnType >( GetProcAddress( reinterpret_cast< HMODULE >( _module ), anEntry.c_str() ) );
      }

      return pfn;
   }
Exemplo n.º 28
0
Arquivo: runcode.c Projeto: xuwenbo/KR
/*
 This is very interesting.

 U need to store the code by yourself.
 and then run it.
 How?  function pointer!!

 Something like shellcode.
*/
int
main(void)
{
    //mov eax, 0x123;
    //ret
    unsigned char code[] = {0xB8, 0x23, 0x01, 0x00, 0x00, 0xC3};

    int (*pfn)(void) = (int (*)(void))(code);

    printf("%d\r\n", pfn());

    return 0;
}
Exemplo n.º 29
0
// Called to start an M.
void*
runtime_mstart(void* mp)
{
	m = (M*)mp;
	g = m->g0;

	initcontext();

	g->entry = nil;
	g->param = nil;

	// Record top of stack for use by mcall.
	// Once we call schedule we're never coming back,
	// so other calls can reuse this stack space.
#ifdef USING_SPLIT_STACK
	__splitstack_getcontext(&g->stack_context[0]);
#else
	g->gcinitial_sp = &mp;
	// Setting gcstack_size to 0 is a marker meaning that gcinitial_sp
	// is the top of the stack, not the bottom.
	g->gcstack_size = 0;
	g->gcnext_sp = &mp;
#endif
	getcontext(&g->context);

	if(g->entry != nil) {
		// Got here from mcall.
		void (*pfn)(G*) = (void (*)(G*))g->entry;
		G* gp = (G*)g->param;
		pfn(gp);
		*(int*)0x21 = 0x21;
	}
	runtime_minit();

#ifdef USING_SPLIT_STACK
	{
	  int dont_block_signals = 0;
	  __splitstack_block_signals(&dont_block_signals, nil);
	}
#endif

	// Install signal handlers; after minit so that minit can
	// prepare the thread to be able to handle the signals.
	if(m == &runtime_m0)
		runtime_initsig();

	schedule(nil);
	return nil;
}
Exemplo n.º 30
0
static void TokenizeLine( char *buf, char delim, void (*pfn)( char * ) )
/**********************************************************************/
{
    char    *s1;
    char    *s2;

    for( s1 = buf; *s1 != '\0'; s1 = s2 ) {
        s2 = s1;
        while( *s2 != '\0' && *s2 != delim )
            ++s2;
        if( *s2 != '\0' )
            *s2++ = '\0';
        pfn( s1 );
    }
}