The following examples illustrate the CLib functions. For additional examples, see NLM and NetWare Libraries for C.
NOTE: taken from ADDLANG.C in the \EXAMPLES directory /********************************************************************* ADDLANG.C ********************************************************************** This example demonstrates how to add a language to the OS supported language list. *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/string.h> #include <nlm/nwthread.h> #include <nlm/nwadv.h> #define MAX_LANGUAGE_ID 999 #define MIN_NON_NETWARE_ID 100 #define MAX_LANGUAGE_NAME 255 int main(void) { int ID = MIN_NON_NETWARE_ID; int len; int ccode = TRUE; char **messageTable; LONG messageCount = 0; LONG languageID; BYTE languageName[MAX_LANGUAGE_NAME]; BYTE name[MAX_LANGUAGE_NAME]; /* Multi-Language enabled NLM applications can load tables of messages for different languages by using this API. Default Language tables can be bound to NLM applications with the messages option in NLMLINK or NLMLINKP. */ LoadLanguageMessageTable(&messageTable, &messageCount, &languageID); /* NLMs can then access messages through the table like this...*/ if(messageCount) printf("The first message in our table is %s.\n", messageTable[1]); languageID = GetCurrentOSLanguageID(); if(!ReturnLanguageName(languageID, languageName)) { printf("The current language on this server is %i : %s\n", languageID, languageName); } /*...find the next available ID number...*/ while(ccode && ID < MAX_LANGUAGE_ID) { ccode = AddLanguage(ID, "TEST LANGUAGE", TRUE); if (ccode) ID++; } if (!ccode) { printf("Test language %i added to OS language list.\n", ID); strcpy(name, "PIG LATIN 0"); /*...find a unique name for this language...*/ ccode = TRUE; while(ccode) { ccode = RenameLanguage(ID, name, TRUE); if (ccode) { len = strlen(name); name[len - 1]++; } } if(!ccode) { ReturnLanguageName(ID, languageName); printf("The name of language %i is %s.\n", ID, languageName); SetCurrentOSLanguageID(ID); languageID = GetCurrentOSLanguageID(); if(!ReturnLanguageName(languageID, languageName)) printf("The current language on this server is %i : %s\n", languageID, languageName); } else printf("Unable to rename test language.\n"); } else printf("Unable to add test language to OS language list.\n"); return(0); }
NOTE: taken from CALENDAR.C in the \EXAMPLES directory /********************************************************************* CALENDAR.C ********************************************************************** This program displays three calendars on the screen; the current month, the previous month, and the next month. *********************************************************************/ #include <nlm/stdio.h> #include <nlm/nwtypes.h> #include <nlm/nwconio.h> #include <nlm/string.h> #include <nlm/time.h> #define FEBRUARY 1 #define NARROW 3 #define WIDE 4 #define PosCursor( row, col ) gotoxy(col,row) #define ClearScreen() clrscr() static int Jump[ 12 ] = { 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6 }; static int MonthDays[ 12 ] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static char *MonthName[ 12 ] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static char *WideTitle = { "Sun Mon Tue Wed Thu Fri Sat" }; static char *NarrowTitle = { "Su Mo Tu We Th Fr Sa" }; int main(void) { time_t curr_time; register struct tm *tyme; ClearScreen(); /* get today’s date */ curr_time = time( NULL ); tyme = localtime( &curr_time ); /* draw calendar for this month */ Calendar( tyme->tm_mon, tyme->tm_year, 10, 26, WIDE, WideTitle ); /* draw calendar for last month */ tyme->tm_mon–; if( tyme->tm_mon < 0 ) { tyme->tm_mon = 11; tyme->tm_year–; } Calendar( tyme->tm_mon, tyme->tm_year, 5, 3, NARROW, NarrowTitle ); /* draw calendar for next month */ tyme->tm_mon += 2; if( tyme->tm_mon > 11 ) { tyme->tm_mon -= 12; tyme->tm_year++; } Calendar( tyme->tm_mon, tyme->tm_year, 5, 56, NARROW, NarrowTitle ); PosCursor( 20, 1 ); return(0); } void Calendar(int month, int year, int row, int col, int width, char *title) { register int start; register int days; register int box_width; register char *str; register int i; box_width = 7 * width - 1; Box( row, col, box_width, 8 ); str = MonthName[ month ]; PosCursor( row - 1, col + 1 + ( box_width - strlen( str ) - 5 ) / 2 ); printf( "%s 19%d\n", str, year ); fflush( stdout ); PosCursor( row + 1, col + 1 ); printf( title ); fflush( stdout ); start = year + year / 4 + Jump[ month ]; if( ( year % 4 == 0 ) && ( month <= FEBRUARY ) ) { –start; } start = start % 7 + 1; if( ( year % 4 == 0 ) && ( month == FEBRUARY ) ) { days = 29; } else { days = MonthDays[ month ]; } row += 3; for( i = 1; i <= days; ++i ) { PosCursor( row, col + width * start - 2 ); printf( "%2d", i ); fflush( stdout ); if( start == 7 ) { printf( "\n" ); fflush( stdout ); ++row; start = 1; } else { ++start; } } } void Box(int row, int col, int width, int height ) { register int i; Line( row, col, width, ’Ú’, ’Ä’, ’¿’ ); Line( row + 1, col, width, ’’, ’ ’, ’’ ); Line( row + 2, col, width, ’Ã’, ’Ä’, ’´’ ); for( i = 3; i <= height; ++i ) { Line( row + i, col, width, ’’, ’ ’, ’’ ); } Line( row + height + 1, col, width, ’À’, ’Ä’, ’Ù’ ); } void Line( int row, int col, int width, char left, char centre, char right ) { char buffer[ 80 ]; buffer[ 0 ] = left; memset( &buffer[ 1 ], centre, width ); buffer[ width + 1 ] = right; buffer[ width + 2 ] = ’\0’; PosCursor( row, col ); printf( buffer ); fflush( stdout ); }
NOTE: taken from CONCOM.C in the \EXAMPLES directory /********************************************************************* CONCOM.C ********************************************************************** This module shows how to add console commands to NetWare. This is useful in situations where an NLM needs console IO support (for instance, an NLM which has no screen). After loading CONCOM.NLM, return to the system console and notice that two new commands are accepted by the NetWare console - CONCOM STAT and CONCOM MISC. *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/string.h> #include <nlm/nwtypes.h> #include <nlm/nwthread.h> #include <nlm/nwerrno.h> #include <nlm/nwadv.h> #include <nlm/nwconio.h> #define HANDLEDCOMMAND 0 #define NOTMYCOMMAND 1 /* Prototypes */ int InstallConsoleHandler(void); static void CCRemoveConsoleHandler(void); void HandleStatRequest(void *dummy); void HandleMiscRequest(void *dummy); void ScheduleStatCommand(void); void ScheduleMiscCommand(void); static LONG CommandLineInterpreter(LONG screenID, BYTE *commandLine ); /* Globals */ static LONG StatCommandThread; static LONG MiscCommandThread; /* Structure used to register/deregister a console handler with the OS */ static struct commandParserStructure ConsoleHandler = {0, CommandLineInterpreter, 0 }; int main(void) { if( BeginThread(HandleStatRequest,NULL,8192,NULL) == EFAILURE ) { printf("ConCom: Couldn’t start Handle Stat Request thread!\n"); exit(1); } if( BeginThread(HandleMiscRequest,NULL,8192,NULL) == EFAILURE ) { printf("ConCom: Couldn’t start Handle Misc Request thread!\n"); exit(1); } ThreadSwitch(); /* let them run at least once... */ if( InstallConsoleHandler() == EFAILURE ) { printf("ConCom: Couldn’t install command parser!\n"); exit( 1 ); } ExitThread(EXIT_THREAD,0); return(0); } static LONG CommandLineInterpreter(LONG screenID, BYTE *commandLine ) { /* All added commands begin with "CONCOM " */ if( !strnicmp("CONCOM ",commandLine,7) ) { /* Figure out which command it is, and then schedule the appropriate thread to handle the request. It,s a good idea to execute quickly here, and return back to the console handler, so all I’m doing is signalling a local semaphore which will wake up the appropriate function. If you want to do all of the work here, you MUST change the CLib context to that of a thread group in your NLM. You can use SetThreadGroupID to do this. Remember to switch it back before you return. */ if( !strnicmp("STAT",&commandLine[7],4) ) { ScheduleStatCommand(); ConsolePrintf("ConCom: STAT request being processed!\r\n"); } else if( !strnicmp("MISC",&commandLine[7],4) ) { ScheduleMiscCommand(); ConsolePrintf("ConCom: MISC request being processed!\r\n"); } else { ConsolePrintf("ConCom: \"%s\" is not a valid command!\r\n", &commandLine[7]); } /* Tell NetWare we handled the command */ return HANDLEDCOMMAND; } /* Tell NetWare that the command isn’t mine */ return NOTMYCOMMAND; } /* This function is called during NLM shutdown */ static void CCRemoveConsoleHandler(void) { UnRegisterConsoleCommand( &ConsoleHandler ); } /* This function installs the handler */ int InstallConsoleHandler(void) { /* Our command line handler interfaces the system operator with this NLM */ ConsoleHandler.RTag = AllocateResourceTag(GetNLMHandle(), "Command Line Processor", ConsoleCommandSignature); if( ! ConsoleHandler.RTag) { printf("Error on allocate resource tag\n"); return EFAILURE; } RegisterConsoleCommand( &ConsoleHandler ); /* The Remove procedure unregisters the console handler */ atexit( CCRemoveConsoleHandler ); return ESUCCESS; } void ScheduleStatCommand(void) { ResumeThread(StatCommandThread); } void HandleStatRequest(void *dummy) { for(;;) { SuspendThread(StatCommandThread = GetThreadID() ); ConsolePrintf("ConCom: Message from the STAT command\n"); } } void ScheduleMiscCommand(void) { ResumeThread(MiscCommandThread); } void HandleMiscRequest(void *dummy) { for(;;) { SuspendThread(MiscCommandThread = GetThreadID() ); ConsolePrintf("ConCom: Message from the MISC command\n"); } }
NOTE: taken from DOWNHAND.C in the \EXAMPLES directory /********************************************************************* DOWNHAND.C ********************************************************************** DOWNHAND.C is an example NLM that demonstrates using the DOWN_SERVER event to warn the operator before allowing the server to go down. Enter 0 at the command line to allow the server to go down. Enter 1 to prompt the operator before allowing the server to go down. Usage: DOWNHAND <arg> 0 Allow the server to go down 1 Prompt operator before downing server *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/nwthread.h> #include <nlm/nwadv.h> /* Prototypes */ LONG WarnProcedure(void (*OutPutFunc)(void *fmt,...),LONG parameter); void ReportProcedure(LONG parameter); void ExitProcedure(void); /* Globals */ int RetValueFromWarnProc=0; /* Let event continue by default */ LONG eventHandle; /* The DOWN_SERVER event handle */ int main(int argc, char *argv[]) { if(argc > 1) RetValueFromWarnProc = atoi(argv[1]); atexit(ExitProcedure); /* register atexit procedure */ eventHandle = RegisterForEvent(EVENT_DOWN_SERVER, ReportProcedure, WarnProcedure); if(eventHandle == -1) { printf("Error registering event DOWN_SERVER!\n"); return(1); } printf("Event registration is complete. Attempt DOWN now...\n"); ExitThread(TSR_THREAD,0); return(0); } /* WarnProcedure() gets called before the event DOWN occurs. This gives you a chance to have the OS warn the operator before allowing the event to continue. In order to get NetWare to display the warning message, return a non-zero value. */ LONG WarnProcedure(void (*OutPutFunc)(void *fmt,...),LONG parameter) { OutPutFunc("Inside WarnProcedure()\r\n"); OutPutFunc("Returning %u to NetWare\r\n",RetValueFromWarnProc); return RetValueFromWarnProc; } /* ReportProcedure() gets called after the event DOWN occurs. This basically is a signal to your NLM that the server has been downed. The parameter for this event is undefined. */ void ReportProcedure(LONG parameter) { printf("Inside ReportProcedure()\r\nThe server has been downed\r\n"); } /* This procedure is called when the NLM is unloaded or exits. */ void ExitProcedure(void) { printf("Unloading DOWNHAND NLM.\r\n"); if(eventHandle != NULL && UnregisterForEvent(eventHandle) != NULL) printf("Error during Unregister of event DOWN_SERVER\r\n"); }
NOTE: taken from NOUNLOAD.C in the \EXAMPLES directory /********************************************************************* NOUNLOAD.C ********************************************************************** NOUNLOAD.C is an example NLM that demonstrates the use of the MODULE_UNLOAD event. This event can be used to detect when an NLM is being unloaded. Enter 0 at the command line to allow the NLM to be unloaded. Enter 1 to prompt the operator before unloading the NLM. Usage: NoUnload <arg> 0 Allow the NLM to be unloaded 1 Prompt operator before unloading *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/nwthread.h> #include <nlm/nwadv.h> /* Prototypes */ LONG WarnProcedure(void (*OutPutProc)(void *fmt, ...), LONG UnloadID); void ReportProcedure(LONG UnloadID); void UnloadProcedure(void); /* Globals */ LONG eventHandle; /* Handle for the MODULE_UNLOAD event */ LONG RetValueFromWarnProc; /* What’s returned from the WarnProc */ LONG myNLMID; /* This is the ID of my NLM */ int main(int argc, char *argv[]) { if(argc > 1) RetValueFromWarnProc = atoi(argv[1]); atexit(UnloadProcedure); eventHandle = RegisterForEvent(EVENT_MODULE_UNLOAD, ReportProcedure, WarnProcedure); if(eventHandle == -1) { printf("Failure to Register for event MODULE_UNLOAD!\n"); exit(1); } /* Get the NLM ID of this NLM. Use this to determine what value is returned from the WarnProcedure. i.e. I only want to have control over the unloading of this NLM. */ myNLMID = FindNLMHandle("NOUNLOAD"); printf("Go ahead and attempt unload...\n"); ExitThread(TSR_THREAD,0); /* TSR this NLM. */ return(0); } /* This procedure is called before the module is unloaded. A non-zero return value will cause NetWare to prompt the operator before unloading the module. */ LONG WarnProcedure(void (*OutPutProc)(void *fmt, ...), LONG UnloadID) { OutPutProc("Inside WarnProcedure\r\n"); if(UnloadID == myNLMID) { OutPutProc("Parameter is %x\r\n",UnloadID); return RetValueFromWarnProc; } return 0; /* Don’t care about other NLMs getting unloaded */ } /* The ReportProcedure is called after the NLM was unloaded. */ void ReportProcedure(LONG UnloadID) { printf("Inside ReportProcedure\r\nNLMID is %x\r\n",UnloadID); } /* This is a generic unload procedure. It simply unregisters the event handling routines we previously registered. */ void UnloadProcedure(void) { if(UnregisterForEvent(eventHandle) != NULL) printf("Failure to unregister MODULE_UNLOAD event!\n"); }
NOTE: taken from TRUSTEE.C in the \EXAMPLES directory /********************************************************************* TRUSTEE.C ********************************************************************** This module illustrates the use of the TRUSTEE_CHANGE event. This event is raised when a trustee is added or deleted to/from the file system. NOTE: This NLM REQUIRES NetWare 3.11 and CLib 3.11 or later. *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/obsolete/fileengd.h> #include <nlm/nwdir.h> #include <nlm/nwsemaph.h> #include <nlm/nwerrno.h> #include <nlm/nwadv.h> /* Prototypes */ void ReportProcedure(LONG parameter); void UnloadProcedure(void); void NetWarePathToDOSPath(BYTE *psp, LONG pathCount); /* Globals */ LONG eventHandle; /* The TRUSTEE_CHANGE event handle */ LONG semaphoreHandle; /* Main thread blocked on this waiting */ /* Save the data passed to the report routine in this structure. Then signal a semaphore to wake up the main thread, it will print the data in the structure. */ struct EventTrusteeChangeStruct etc; int main(void) { BYTE pathString[255]; BYTE volumeName[32]; LONG pathCount; semaphoreHandle = OpenLocalSemaphore(0); if(semaphoreHandle == -1 ) { printf("Could not open a local semaphore\n"); return(1); } atexit(UnloadProcedure); /* register unload procedure */ eventHandle = RegisterForEvent(EVENT_TRUSTEE_CHANGE, ReportProcedure, NULL); if(eventHandle == -1) { printf("Error registering event TRUSTEE_CHANGE!\n"); return(1); } printf("Event registration is complete.\r\n"); /* Main Loop. Wait for work. */ while(1) { WaitOnLocalSemaphore( semaphoreHandle ); /* A Trustee has been added or deleted, print the info */ printf("Trustee change detected for object %x\r\n",etc.objectID); switch( etc.changeFlags ) { case EVENT_NEW_TRUSTEE: printf("Trustee added to file system. Rights granted %x\r\n", etc.newRights); break; case EVENT_REMOVE_TRUSTEE: printf("Trustee removed from file system.\r\n"); break; default: printf("Unknown changeFlags %x.\r\n",etc.changeFlags); break; } if(NULL == FEMapVolumeAndDirectoryToPath(etc.volumeNumber, etc.entryID, pathString, &pathCount)) { /* Convert the NetWare-Style path to a DOS-Style path */ NetWarePathToDOSPath( pathString, pathCount ); GetVolumeName(etc.volumeNumber,volumeName); printf("Change made to %s%s\r\n",volumeName,pathString); } else { printf("FEMapVolumeAndDirectoryToPath failed: %x\r\n", NetWareErrno); } } } /* This EVENT only supports a ReportProcedure. The procedure gets called every time a trustee is added or removed to/from the file system. */ void ReportProcedure(LONG parameter) { /* Save the data in our local structure */ etc = *(struct EventTrusteeChangeStruct *)parameter; /* Wake up the main thread */ SignalLocalSemaphore(semaphoreHandle); } /* This procedure is called when the NLM is unloaded */ void UnloadProcedure(void) { printf("Inside UnloadProcedure() Procedure\r\n"); if(UnregisterForEvent(eventHandle) != NULL) printf("Error during Unregister of event TRUSTEE_CHANGE\r\n"); CloseLocalSemaphore(semaphoreHandle); } /* Convert a NetWare-Style path to a DOS-Style path, in place */ void NetWarePathToDOSPath(BYTE *psp, LONG pathCount) { LONG componentLen; componentLen = *psp; /* remember the length */ *psp++ = ’:’; /* put volume separator */ psp += componentLen; /* get to next component */ while( –pathCount ) { componentLen = *psp; /* remember length */ *psp = ’/’; /* put directory separator */ psp += componentLen + 1; /* to next component */ } *psp = NULL; /* put null terminator */ }
NOTE: taken from HELLO.C in the \EXAMPLES directory /********************************************************************* HELLO.C ********************************************************************** This module shows how to write a "Hello, world" NLM. To run this NLM, simply load HELLO.NLM on the server, and it will print the message "Hello, world" on the screen. HELLO.C uses symbols in CLIB.IMP, THREADS.IMP, and NLMLIB.IMP. *********************************************************************/ #include <nlm/stdio.h> void main(void) { printf( "Hello, world\n" ); }
NOTE: taken from ATEXIT.C in the \EXAMPLES directory /********************************************************************* ATEXIT.C ********************************************************************** This example NLM illustrates the use of atexit function(s). An atexit() function is one that is called by CLib AFTER the NLM’s threads have been destroyed. This is not a workable solution for NLMs that use stack-based resources which are hidden from the atexit() functions. For those types of situations, you would want to use a signal handler, so you can "tell" the threads to shutdown themselves. See the SIGTERM example for an illustration of signal handling. notes: 1. The atexit() functions are always called when the NLM is exiting, unless the NLM is exiting via abort(). Remember that the SIGABRT signal calls abort()! 2. All of your NLM’s threads have been destroyed BEFORE any of these functions are called. 3. You can call CLib functions from your atexit functions. You must only free resources, however, don’t try and allocate new resources! i.e. don’t try to open files, or service queue jobs, or start new threads, ... 4. Your screen is still intact, so you can use any of the standard library’s IO functions here. i.e. printf,... *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/nwtypes.h> #include <nlm/nwsemaph.h> #include <nlm/nwerrno.h> FILE *myOpenFile; /* file to open */ LONG mySemaphore; /* semaphore to open */ char *myMemPtr; /* memory to allocate */ /* Following are the atexit functions to register. They are called in a last-in first-out fashion, so if you will have dependancies keep that in mind. */ /* This function closes my file, if it was opened. */ void CloseMyFile() { if( myOpenFile != NULL ) { fclose( myOpenFile ); printf("myOpenFile was closed...\n"); } else { printf("myOpenFile was not open...\n"); } } /* This function closes my semaphore, if it was opened. */ void CloseMySemaphore() { if( mySemaphore != NULL ) { CloseLocalSemaphore( mySemaphore ); printf("mySemaphore was closed...\n"); } else { printf("mySemaphore was not opened...\n"); } } /* This function frees my memory, if it was allocated. */ void FreeMyMemory() { if( myMemPtr != NULL ) { free( myMemPtr ); printf("myMemPtr was freed...\n"); } else { printf("myMemPtr was not allocated...\n"); } } int main(void) { if( (myMemPtr = malloc( 200 )) == NULL ) { printf("\n Could not allocate memory\n"); } if( (mySemaphore = OpenLocalSemaphore( 1 )) == EFAILURE ) { printf("\n Could not open semaphore\n"); } if((myOpenFile = fopen( "SYS:MYFILE", "r" )) == NULL ) { printf("\n Could not open my file\n"); } if( atexit( CloseMyFile ) == EFAILURE ) { printf("\n Could not register CloseMyFile\n"); } if( atexit( CloseMySemaphore ) == EFAILURE ) { printf("\n Could not register CloseMySemaphore\n"); } if( atexit( FreeMyMemory ) == EFAILURE ) { printf("\n Could not register FreeMyMemory\n"); } printf(" Okay, I’m ready. Unload me or Press ESC\n"); while(1) { if( getch() == 0x1b ) break; /* break on ESCAPE key */ printf("\n\n Press ESC to have the NLM unload itself...\n"); } /* When the NLM exits on its own, the registered atexit functions are called by CLib... */ return(0); }
NOTE: taken from ATUNLOAD.C in the \EXAMPLES directory /********************************************************************* ATUNLOAD.C ********************************************************************** This example NLM illustrates the use of an AtUnload function. An AtUnload function is one that is called by CLib AFTER the NLM’s threads have been destroyed. This is not a workable solution for NLMs that use stack-based resources which are hidden from the AtUnload function. For those types of situations, you would want to use a signal handler, so you can "tell" the threads to shutdown themselves. See SIGTERM example for an illustration of signal handling. notes: 1. The AtUnload function is called ONLY if the NLM is being unloaded from the command line. Thus, you would most likely use this when your NLM will never exit on its own. 2. All of your NLM’s threads have been destroyed BEFORE this function is called. 3. You can call CLib functions from your AtUnload function. You must only free resources, however, don’t try and allocate new resources! i.e. don’t try to open files, or service queue jobs, or start new threads, ... 4. Your screen is still intact, so you can use any of the standard library’s IO functions here. i.e. printf,... *********************************************************************/ #include <nlm/stdio.h> #include <nlm/malloc.h> #include <nlm/nwtypes.h> #include <nlm/nwthread.h> char *myMemPtr; /* pointer to my memory */ /* This is the AtUnload function called by CLib after the NLM’s threads are destroyed. It should do all cleanup before returning, unless you are also using atexit functions. The function is registered via the CLib function AtUnload(). See the code in main(). */ void NLMsAtUnloadFunction() { if( myMemPtr != NULL ) free( myMemPtr ); printf("Example#2 NLM has cleaned up its resources...\n"); } int main(void) { if( (myMemPtr = malloc( 200 )) == NULL ) { printf("\n\n\n Could not allocate memory!\n\n"); printf(" Go ahead an unload me from the command line anyway...\n\n"); } AtUnload( NLMsAtUnloadFunction ); /* register unload function */ printf(" Okay, I’m ready. Unload me!\n"); while(1) { if( getch() == 0x1b ) break; /* break on ESCAPE key */ printf("\n\n Press ESC to have the NLM unload itself...\n"); } /* If the NLM unloads itself, the AtUnload function is NOT called! So, I’ll call it myself to free my resources... */ NLMsAtUnloadFunction(); return(0); }
NOTE: taken from CHECK.C in the \EXAMPLES directory /********************************************************************* CHECK.C ********************************************************************** This example NLM illustrates the use of a CHECK function. A CHECK function is one that is called by NetWare BEFORE an NLM is unloaded. It allows the function to determine if it is "safe" to unload the NLM, and then convey that information to the console operator via the NetWare System Console screen. To generate the warning, enter a 1 (non-zero value) at the command line: LOAD CHECK 1 To skip the warning, enter a 0 at the command line: LOAD CHECK 0 notes: 1. The function returns non-zero to tell NetWare to issue a warning before the NLM is unloaded. 2. The function returns zero to tell NetWare that it is okay for the NLM to be unloaded. 3. The function should execute quickly, and should NOT relinquish control. 4. The function should NOT call any CLib functions. 5. Messages can be printed using ConsolePrintf 6. Check functions will not work properly if they have a program offset of zero. To avoid this problem, don’t list the check function first in your program (for instance, this example declares main() before CheckFunction() ). 7. To build a makefile for this example using QMK386, use the following syntax to register the check function through the linker: QMK386 CHECK /ocCheckFunction *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <ntypes.h> #include <nlm/nwtypes.h> #include <nlm/nwconio.h> int NLMisBusyRightNow = 0; /* This is the CHECK function. It is called by NetWare before the NLM is unloaded. It returns non-zero to signal the OS to prompt the operator before unloading. It returns zero to tell the OS it is okay to unload the NLM. */ int main(int argc, char *argv[]) { if( argc > 1 ) NLMisBusyRightNow = atoi(argv[1]); /* pick up flag */ printf("\r\n\n\n The value of NLMisBusyRightNow is %d\n", NLMisBusyRightNow); printf("\n\n Go ahead and unload it from the command line...\n"); while(1) { if( getch() == 0x1b ) break; /* break on ESCAPE key */ printf("\n\n Press ESC to have the NLM unload itself...\n"); } /* Returning from the last thread of execution will unload the NLM */ return(0); } int CheckFunction() { ConsolePrintf("\n CheckFunction called.\n"); if( NLMisBusyRightNow != 0 ) { ConsolePrintf("NLM currently busy! Do not unload it right now!\r\n"); return(1); } return(0); }
NOTE: taken from UNLOADNO.C in the \EXAMPLES directory /********************************************************************* UNLOADNO.C ********************************************************************** This module demonstrates how to prevent your NLM from being unloaded. It uses a check function to accomplish this task. Check functions such as NoUnload are registered through the linker. Use the following syntax with QMK386 to generate a makefile that registers this check function: QMK386 UNLOADNO /ocNoUnload *********************************************************************/ #include <nlm/stdio.h> #include <nlm/nwtypes.h> #include <nlm/nwconio.h> #include <nlm/nwthread.h> /* The following check function is called by NetWare when someone attempts to unload my NLM. It will ungetch() an ’n’ onto the system console, and return non-zero to request that the OS prompt the operator before unloading. Since the ’n’ has been pushed onto the console, it will automatically return to the prompt without allowing the operator to unload the NLM. Make sure and allow for some other mechanism for unloading, or your NLM will remain loaded until the server is downed. */ static LONG MyTGID; int main(void) { MyTGID = GetThreadGroupID(); printf("Go ahead and try to unload this NLM!\n"); printf("<Press any key to exit from here>\n"); getch(); return(0); } int NoUnload(void) { LONG OldTGID; LONG OldScrID; LONG NewScrID; /* Establish context for this thread. */ OldTGID = SetThreadGroupID(MyTGID); OldScrID = GetCurrentScreen(); NewScrID = CreateScreen("System Console",0); /* Make sure the current screen is the system console */ if( OldScrID != NewScrID) SetCurrentScreen(NewScrID); /* push an ’n’ onto the console */ ungetch(’n’); /* Reset the screen ID if necessary */ if( OldScrID != NewScrID) SetCurrentScreen(OldScrID); DestroyScreen(NewScrID); SetThreadGroupID(OldTGID); return(1); /* ask NetWare to supply a warning message */ }
NOTE: taken from SIGTERM.C in the \EXAMPLES directory /********************************************************************* SIGTERM.C ********************************************************************** This example NLM illustrates the use of signal handlers. Signal handlers provide a means of performing a graceful shutdown in the NLM environment. The big difference between signal handlers and AtUnload or atexit functions is that signal handlers are called BEFORE the NLM’s threads are destroyed. This way, you can have the threads shut down themselves. notes: 1. This NLM will illustrate how to handle the SIGTERM signal. This signal is raised by CLib if the NLM is unloaded from the command line. 2. If your NLM exits on its own, YOU must raise SIGTERM! 3. You can call CLib functions from your signal handler. 4. Your screen is still intact, so you can use any of the standard library’s IO functions here. i.e. printf,... 5. You can relinquish control. *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <ntypes.h> #include <nlm/signal.h> #include <nlm/nwtypes.h> #include <nlm/nwthread.h> #include <nlm/nwerrno.h> int ThreadCounter; /* the number of threads that are running */ int ShutDownFlag; /* set to TRUE by the SIGTERM signal handler */ /* Following is the function that I will register for handling the SIGTERM signal. It will be called by CLib if the NLM is unloaded, or by myself if you hit the escape key... */ #pragma off(unreferenced); void MySignalHandler(int sigtype) /* sigtype is SIGTERM, SIGABRT, ... */ #pragma on(unreferenced); { ShutDownFlag = TRUE; /* tell the threads to shutdown */ printf("Inside signal handler, waiting for threads to stop...\n"); while( ThreadCounter > 0 ) { delay( 500 ); /* wait half a second... */ } printf("Inside signal handler, threads have stopped...\n"); } /* This is the thread running. More than one instance may be running. */ void MyThread( LONG *AmtOfMem ) { char *myMemPtr; int ThreadID = GetThreadID(); ++ThreadCounter; if( (myMemPtr = malloc( *AmtOfMem )) == NULL ) { printf("\n Thread %08x: Could not allocate memory!\n", ThreadID); } printf(" Thread %08x: Waiting...\n", ThreadID); while( ShutDownFlag != TRUE ) { ThreadSwitch(); /* just spin here... */ } if( myMemPtr != NULL ) free( myMemPtr ); printf(" Thread %08x: Exiting...\n", ThreadID); –ThreadCounter; } main(int argc, char *argv[]) { LONG amountOfMemory = 200; int numThreads = 3,i; if( argc > 1 ) amountOfMemory = atoi( argv[1] ); printf("memory each thread will allocate = %d\n",amountOfMemory); for( i = 0; i < numThreads; ++i ) { if( BeginThread(MyThread,NULL,NULL,&amountOfMemory) == EFAILURE ) { printf("Could not start thread number %d\n",i); } } signal(SIGTERM, MySignalHandler); /* register signal handler */ printf(" Okay, the threads have started. Unload me or Press ESC!\n"); while(1) { if( getch() == 0x1b ) break; /* break on ESCAPE key */ printf("\n\n Press ESC to have the NLM unload itself...\n"); } /* When the NLM exits on its own, YOU must raise SIGTERM! */ raise(SIGTERM); }
NOTE: taken from ACCESS.C in the \EXAMPLES directory /********************************************************************* ACCESS.C *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/string.h> #include <nlm/unistd.h> #include <nlm/nwerrno.h> #include <nlm/errno.h> #include <nlm/sys/stat.h> int main(void) { int rc; char filename[200]; struct stat statblk; errno = 0; printf("enter filename: "); gets(filename); rc = access(filename, W_OK | R_OK); if(rc) { printf("access returned %d\n", rc); printf("%s\nNetWareErrno=%d\n\n", strerror(errno), NetWareErrno); exit(1); } rc = stat(filename, &statblk); if(rc) { printf("stat returned %d\n", rc); printf("%s\nNetWareErrno=%d\n\n", strerror(errno), NetWareErrno); exit(1); } printf("st_dev = %d\n",statblk.st_dev); printf("st_ino = %d\n",statblk.st_ino); printf("st_mode = %hu\n",statblk.st_mode); printf("st_nlink = %hd\n",statblk.st_nlink); printf("st_uid = %d\n",statblk.st_uid); printf("st_gid = %hd\n",statblk.st_gid); printf("st_rdev = %d\n",statblk.st_rdev); printf("st_size = %d\n",statblk.st_size); printf("st_atime = %d\n",statblk.st_atime); printf("st_mtime = %d\n",statblk.st_mtime); printf("st_ctime = %d\n",statblk.st_ctime); printf("st_btime = %d\n",statblk.st_btime); printf("st_attr = %d\n",statblk.st_attr); printf("st_archivedID = %d\n",statblk.st_archivedID); printf("st_updatedID = %d\n",statblk.st_updatedID); return(0); }
NOTE: taken from TEMPNAME.C in the \EXAMPLES directory /********************************************************************* TEMPNAME.C ********************************************************************** This example demonstrates the tmpnam() function. OUTPUT: The new name in ’myBuffer’ is: _T-00001.TMP The new name in the ’static buffer’ is: _T-00002.TMP The name that ’ptr’ points to is: _T-00003.TMP *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> int main(void) { char myBuffer[L_tmpnam]; char *ptr; tmpnam(myBuffer); printf("The new name in ’myBuffer’ is: %s\n",myBuffer); ptr = tmpnam(NULL); printf("The new name in the ’static buffer’ is: %s\n", ptr); ptr = (char *) malloc(L_tmpnam); tmpnam(ptr); printf("The name that ’ptr’ points to is: %s\n", ptr); free(ptr); return(0); }
/********************************************************************* This example demonstrates the functions _makepath and _splitpath. *********************************************************************/ #include <nlm/stdio.h> #include <nlm/nwfileio.h> int main(void) { char full_path[_MAX_PATH]; char vol[_MAX_VOLUME]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; _makepath(full_path,"SYS","acct\\dueacct\\","test","c"); printf("\nFULL PATH: \n %s\r\n",full_path); _splitpath(full_path,vol,dir,fname,ext); printf("\nCOMPONENTS AFTER _splitpath\r\n"); printf(" vol : %s\r\n",vol); printf(" dir : %s\r\n",dir); printf(" fname : %s\r\n",fname); printf(" ext : %s\r\n",ext); return(0); }
NOTE: taken from UNLINK.C in the \EXAMPLES directory /********************************************************************* UNLINK.C ********************************************************************** This example demonstrates how to delete a file using unlink(). *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/unistd.h> int main(int argc, char *argv[]) { if(argc != 2) { printf("\nusage: UNLINK <filename>"); exit(1); } if(unlink(argv[1])) printf("\nCOULD NOT DELETE: %s", argv[1]); else printf("\nDELETED FILE: %s", argv[1]); return(0); }
NOTE: taken from DIRECTRY.C in the \EXAMPLES directory /********************************************************************* DIRECTRY.C ********************************************************************** USAGE: DIRECTRY <PATH> EXAMPLE: DIRECTRY SYS:\EXAMPLES\*.* *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/errno.h> #include <nlm/dirent.h> int main(void) { char path[255]; int cnt = 0; DIR *dirStructP; DIR *direntp; printf("Enter the path to do readdir() on: "); scanf("%s", path); if((dirStructP = opendir(path)) != NULL) { while((direntp = readdir(dirStructP)) != NULL) { cnt++; /* possibly dump out file info here...*/ } printf("%d entries scanned\n", cnt); closedir(dirStructP); } else { printf("opendir returned errno: %#x\n", errno); exit(1); } return(0); }
NOTE: taken from ECHOSERV.C in the \EXAMPLES directory /********************************************************************** ECHOSERV.C ********************************************************************** This module illustrates how to create an NLM Server that uses the NCP Extension APIs in CLib. ECHOSERV.C is NLM-specific but its counterpart ECHOCLNT.C can be run from a server or a workstation. *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/nwncpx.h> #include <nlm/nwadv.h> #include <nlm/nwthread.h> #include <nlm/nwconio.h> #include <nlm/nwerrno.h> /* Prototypes */ BYTE EchoServer(NCPExtensionClient *client, BYTE *requestData, LONG requestDataLen, BYTE *replyData, LONG *replyDataLen); void EchoServerConnDownHandler(LONG connection, LONG eventType); /* Globals */ int myThreadGroupID; char NCPExtName[] = "ECHO SERVER"; struct queryDataStruct { LONG CharsEchoed; LONG ErrorsServicingRequests; LONG unused[6]; } *queryData; int main(void) { int rc; myThreadGroupID = GetThreadGroupID(); ConsolePrintf("Registering NCP Extension: %s\n", NCPExtName); if(SetThreadContextSpecifier(GetThreadID(), NO_CONTEXT) != ESUCCESS) { ConsolePrintf("Error doing pre-registration processing, %s not loaded\n", NCPExtName); return 1; } rc = NWRegisterNCPExtension(NCPExtName, EchoServer, EchoServerConnDownHandler, NULL, 1, 0, 0, &queryData); if (rc) { ConsolePrintf("Error %d registering NCP Extension: %s\n", rc, NCPExtName); return 2; } queryData->CharsEchoed = 0; queryData->ErrorsServicingRequests = 0; printf("Press any key to unload echo server.\n"); getch(); rc = NWDeRegisterNCPExtension(queryData); if(rc) { ConsolePrintf("Error %d Deregistering NCP Extension: %s\n", NCPExtName); return 3; } ConsolePrintf("NCP Extension %s Deregistered\n", NCPExtName); return 0; } /* A note about checking parameters: These requests are coming over the wire and little is known about the entity formulating them. It is up to the developer to decide how much to trust the incoming requests, this example checks the length of the parameters requestDataLen and replyDatalen. */ BYTE EchoServer(NCPExtensionClient *client, BYTE *requestData, LONG requestDataLen, BYTE *replyData, LONG *replyDataLen) { int savedThreadGroupID; int rc; if(requestDataLen < 1) { /* Expect exactly 1, there’s a problem if it’s 0 */ ConsolePrintf("%s reports bad parameters on call from client at " "connection: %ld, task: %ld\n", client->connection, client->task); queryData->ErrorsServicingRequests++; return 0x5F; } savedThreadGroupID = GetThreadGroupID(); if(SetThreadGroupID(myThreadGroupID) == EFAILURE) { queryData->ErrorsServicingRequests++; return 0x5E; } if (putchar(*(char *)requestData) == EOF) { ConsolePrintf("%s couldn’t echo char to screen!\n", NCPExtName); queryData->ErrorsServicingRequests++; rc = 0x5D; goto exit0; } /* Check the length of the reply data buffer since we don’t have control over the caller. (Shouldn’t write to memory when unsure of the size.) */ if (*replyDataLen < 1) { /* Expect exactly 1, there’s a problem if it’s 0 */ ConsolePrintf("%s reports bad parameters on call from client at " "connection: %ld, task: %ld\n", client->connection, client->task); queryData->ErrorsServicingRequests++; rc = 0x5C; goto exit0; } *replyDataLen = 1; *replyData = *requestData; queryData->CharsEchoed++; rc = 0; exit0: if(SetThreadGroupID(savedThreadGroupID) == EFAILURE) ConsolePrintf("%s reports error restoring callers thread group context\n", NCPExtName); return rc; } void EchoServerConnDownHandler(LONG connection, LONG eventType) { char *eventString; /* NOTE: No context is needed in this callback, so we don’t set the thread group ID. */ switch(eventType) { case CONNECTION_BEING_RESTARTED: { eventString = "connection being restarted"; break; } case CONNECTION_BEING_KILLED: { eventString = "connection being killed"; break; } case CONNECTION_BEING_LOGGED_OUT: { eventString = "connection being logged out"; break; } case CONNECTION_BEING_FREED: { eventString = "connection being freed"; break; } default: { eventString = "unknown event type"; } } ConsolePrintf("\n%s got notification of connection event on conn #%d\n" "event = %s\n", NCPExtName, connection, eventString); }
NOTE: taken from RENTRANT.C in the \EXAMPLES directory /********************************************************************* RENTRANT.C ********************************************************************** RENTRANT.C demonstrates the use of an NLM as a multiple-loadable daemon which can perform a task as scheduled with different copies of the NLM running continually in the background. This example NLM illustrates the use of a START function. The following command uses QMK386 to generate a Watcom makefile for RENTRANT.C: QMK386 RENTRANT /nr /x /osMultipleLoadFilter /nr = ReEntrant /x = no default screen for NLM /osMultipleLoadFilter = register start function *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/string.h> #include <ntypes.h> #include <nlm/nwthread.h> #include <nlm/nwconio.h> #include <nlm/time.h> #define kMaxArguments 12 #define SECONDS_SINCE_START clock() / 100 #define kUsage "\nUsage:\n"\ "Rentrant <perform-interval>\n"\ "perform-interval (every) [[days:]hours:]minutes\n\n" /* Globals */ typedef struct { int Days; int Hours; int Minutes; int Executions; clock_t TotalSeconds; } Globals; typedef struct resource_list { struct resource_list *next; int screenHandle; } ResourceList; typedef void (*PVF) ( void *); int gAlreadyLoaded = 0; int gMainThreadGroupID; char *gProgramName = "Rentrant"; Globals *gG; ResourceList *gResList = (ResourceList *) NULL; typedef struct LoadDefinitionStructure *LoadDefStructPtr; typedef struct ScreenStruct *ScreenStructPtr; /* Prototypes */ void StrCpy(register char *t, register char *s); int ParseCommandLine(char *commandLine, int *argc, char *argv[]); void DisplayPerformances(Globals *g); void DisplayTimeLeft(clock_t timeLeft, int doZero); int LogScreenHandle(int scrH); void CleanupResource(int which); void Cleanup(void); extern LONG _Prelude( ); LONG MultipleLoadFilter(LoadDefStructPtr NLMHandle, ScreenStructPtr initErrorScreenID, BYTE *cmdLineP, BYTE *loadDirPath, LONG uninitDataLen, LONG NLMFileHandle, LONG cdecl (*readFunc)()); /********************************************************************* ** Main Routine */ void main(int argc, char *argv[]) { int firstTime, first, second, third; int scrH, myThreadGroupID; char **argV; char *args[kMaxArguments]; char commandLine[200+1]; char threadName[17+1+13]; char ch; Globals g; register clock_t whenToExecuteNext; register int i; memset(&g, 0, sizeof(Globals)); gG = &g; /* for debugging... */ if(!gAlreadyLoaded) { gMainThreadGroupID = GetThreadGroupID(); RenameThread(gMainThreadGroupID, "Rentrant–main"); gAlreadyLoaded = 1; firstTime = TRUE; argV = argv; AtUnload(Cleanup); } else { sprintf(threadName, "Rentrant–#%d", gAlreadyLoaded); myThreadGroupID = GetThreadGroupID(); RenameThread(myThreadGroupID, threadName); gAlreadyLoaded++; firstTime = FALSE; argV = args; } scrH = CreateScreen("Sample Reentrant NLM", 0); if(!scrH) { ConsolePrintf("\nUnable to create screen..."); goto NoScreenExit; } LogScreenHandle(scrH); SetCurrentScreen(scrH); printf("\nSample Reentrant NLM: %d\n", gAlreadyLoaded); if(!firstTime) /* command line must be separately parsed... */ { argV[0] = gProgramName; /* as passed to BeginThreadGroup() */ StrCpy(commandLine, (char *) argc); if(ParseCommandLine(commandLine, &argc, argV+1)) { ConsolePrintf("%c", 0x07); goto UsageError; } argc++; /* to compensate for missing program name... */ ConsolePrintf("\nCommand:\n"); /* debugging only, can remove... */ for (i = 0; i < argc; i++) ConsolePrintf("%s ", argV[i]); } if(argc < 2) { UsageError : ConsolePrintf(kUsage, argV[0]); goto Exit; } first = second = third = -1; sscanf(argV[1], "%d:%d:%d", &first, &second, &third); if(first != -1 && second != -1 && third != -1) { g.Days = first; g.Hours = second; g.Minutes = third; } else if(first != -1 && second != -1) { g.Hours = first; g.Minutes = second; } else /* ’first’ must be nonzero */ { g.Minutes = first; } /* ** Loop awaiting keyboard interrupt to halt this daemon. Yield to ** server very frequently. Wake up to perform work periodically... */ gotoxy(0, 23); printf("Press ’q’ at any time to halt this daemon..."); g.TotalSeconds = g.Days * 24 * 60 * 60 + g.Hours * 60 * 60 + g.Minutes * 60; whenToExecuteNext = g.TotalSeconds; while(TRUE) { if(whenToExecuteNext < SECONDS_SINCE_START) { whenToExecuteNext += g.TotalSeconds; DisplayTimeLeft(0L, TRUE); /* perform work stuff here... */ { gotoxy(0, 5); printf("Performing..."); for (i = 0; i < 100000; i++); gotoxy(0, 5); printf(" "); } g.Executions++; DisplayPerformances(&g); } if(kbhit()) { ch = getch(); if (ch == ’q’ || ch == ’Q’) break; } DisplayTimeLeft(whenToExecuteNext - SECONDS_SINCE_START, FALSE); ThreadSwitchLowPriority(); } Exit : CleanupResource(scrH); NoScreenExit : ExitThread(EXIT_THREAD, 0); } void StrCpy(register char *t, register char *s) { while (*t++ = *s++); } LONG MultipleLoadFilter(LoadDefStructPtr NLMHandle, ScreenStructPtr initErrorScreenID, BYTE *cmdLineP, BYTE *loadDirPath, LONG uninitDataLen, LONG NLMFileHandle, LONG cdecl (*readFunc)()) { int myThreadGroupID; if(!gAlreadyLoaded) /* first time through */ return _Prelude(NLMHandle, initErrorScreenID, cmdLineP, loadDirPath, uninitDataLen, NLMFileHandle, readFunc); /* subsequent times through... */ myThreadGroupID = SetThreadGroupID(gMainThreadGroupID); BeginThreadGroup((PVF) main, NULL, NULL, cmdLineP); SetThreadGroupID(myThreadGroupID); return 0L; } /* into argc/argv format... */ int ParseCommandLine(char *commandLine, int *argc, char *argv[]) { register char *p = commandLine; if (!p) return -1; *argc = 0; while(TRUE) { argv[(*argc)++] = p; /* register last argument found... */ while (*p && *p != ’ ’) p++; if (!*p) break; *p++ = ’\0’; } return 0; } void DisplayPerformances(Globals *g) { gotoxy(0, 3); printf("%d ", g->Executions); } /* in seconds */ void DisplayTimeLeft(clock_t timeLeft, int doZero) { clock_t days, hours, minutes; if (doZero) { days = hours = minutes = 0; goto Display; } /* ** Remove days, hours and finally minutes from 100ths of seconds ** left */ days = timeLeft / 86400; /* seconds per day */ timeLeft -= days * 86400; hours = timeLeft / 3600; /* seconds per hour */ timeLeft -= hours * 3600; minutes = timeLeft / 60; /* seconds per minute */ Display : gotoxy(0, 2); printf("Next performance: %02d day", days); if (days != 1) putchar(’s’); putchar(’ ’); printf("%02d hour", hours); if (hours != 1) putchar(’s’); putchar(’ ’); printf("%02d minute", minutes); if (minutes != 1) putchar(’s’); else putchar(’ ’); } int LogScreenHandle(int scrH) { register ResourceList *r = gResList; if(!r) { r = gResList = (ResourceList *) malloc(sizeof(ResourceList)); if (!r) return -1; } else { while (r->next) /* (find end of list...) */ r = r->next; r->next = (ResourceList *) malloc(sizeof(ResourceList)); r = r->next; if (!r) return -1; } r->next = (ResourceList *) NULL; r->screenHandle = scrH; return 0; } void CleanupResource(int which) { register ResourceList *next, *prev = (ResourceList *) NULL, *r = gResList; while(r) { next = r->next; if (r->screenHandle == which) { DestroyScreen(r->screenHandle); if (prev) /* patch holes left... */ prev->next = next; else gResList = next; free(r); break; } prev = r; r = next; } } void Cleanup( void ) { register ResourceList *next, *r = gResList; while(r) { next = r->next; DestroyScreen(r->screenHandle); free(r); r = next; } }
NOTE: taken from SALVAGE.C in the \EXAMPLES directory /********************************************************************* SALVAGE.C ********************************************************************** This NLM salvages files from a NetWare volume. It also supports purging files. *********************************************************************/ #include <nlm/stdio.h> #include <nlm/nwtypes.h> #include <nlm/nwtime.h> #include <nlm/nwconio.h> #include <nlm/nwfile.h> #include <nlm/string.h> int main(void) { int rc; int commandChar,purgeAllFlag = 0; char newFileName[100]; char fullPathName[200]; struct _DOSTime filTim; struct _DOSDate filDat; char scanDirectory[100], *charP; long nen = - 1; DIR dirP; printf("Directory to scan: "); gets(scanDirectory); if(!scanDirectory[0]) { scanDirectory[0] = ’\\’; scanDirectory[1] = 0; } /* print screen header */ clrscr(); printf(" File Name Size Attr Date "); printf(" Time Ser# Vol# Seq#\r\n"); printf("———— ——– —— ——–"); printf(" ——– —- —- —-\r\n"); gotoxy( 0, 24); printf("A - purge all; P - purge; S - salvage;"); printf(" <enter> - next file; X - exit" ); SetScreenRegionAttribute( 24, 1, 0x70 ); gotoxy( 0, 2); while (!ScanErasedFiles(scanDirectory, &nen, &dirP)) { filTim = *(struct _DOSTime *) &dirP.d_time; filDat = *(struct _DOSDate *) &dirP.d_date; strcpy(newFileName,dirP.d_name); if ((charP = strchr( newFileName, ’.’ ) ) == NULL) charP = " "; else *charP++ = 0; /* overwrite period with a zero */ if (wherey() == 24) { ScrollScreenRegionUp( 2, 22 ); gotoxy( 0, 23 ); } printf("%-8.8s %-3.3s %8d 0x%04x %02u/%02u/%02u", newFileName, charP, dirP.d_size, dirP.d_attr, filDat.month, filDat.day, filDat.yearsSince80+80); printf(" %02u:%02u:%02u %4d %4d %4d\r\n", filTim.hour, filTim.minute, filTim.bisecond, dirP.d_ino, dirP.d_dev, nen & 0xFFFFFF); /* underline current file, un-underline previous file */ SetScreenRegionAttribute(wherey()-1, 1, 10 ); SetScreenRegionAttribute(wherey()-2, 1, 7 ); if(!purgeAllFlag) { commandChar = getch(); if(commandChar == ’A’) purgeAllFlag = 1; } if((commandChar == ’p’) || (commandChar == ’P’) || purgeAllFlag) { strcpy(fullPathName,scanDirectory); if(scanDirectory[1]) strcat(fullPathName,"\\"); strcat(fullPathName,dirP.d_name); if (rc = PurgeErasedFile( fullPathName, nen )) printf("Could Not Purge File %s; error = %d\r\n", fullPathName,rc); } else if((commandChar == ’s’) || (commandChar == ’S’)) { if (wherey() == 24) { ScrollScreenRegionUp( 2, 22 ); gotoxy( 0, 23 ); } printf("new file name: "); gets(newFileName); strcpy(fullPathName,scanDirectory); if(scanDirectory[1]) strcat(fullPathName,"\\"); strcat(fullPathName,dirP.d_name); if (rc = SalvageErasedFile( fullPathName, nen, newFileName)) printf("Could Not Salvage File %s; error = %d\r\n", dirP.d_name,rc); } else if((commandChar == ’x’) || (commandChar == ’X’)) { break; } } return(0); }
NOTE: taken from WHEREIS.C in the \EXAMPLES directory /********************************************************************* WHEREIS.C ********************************************************************** This module finds all files matching the given file specification. It accepts NetWare-style paths. *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/string.h> #include <ntypes.h> #include <nlm/nwconio.h> #include <nlm/ctype.h> #include <nlm/unistd.h> #include <nlm/nwdir.h> #include <nlm/dirent.h> #define skipspace( x ) while( isspace( *x ) ) ++x #define nextspace( x ) while( *x && !isspace( *x ) ) ++x #define CWS 0 #define CWV 1 #define CWP 2 #define ALL 99 /* Globals */ extern char *GetWorkArea(void); extern char *next_arg(char *); char fid[100]; static breakkey = FALSE; int main(int argc, char *argv[]) { int hscrn; if (argc < 2) { ConsolePrintf("\nUsage: WHEREIS <filename>\n"); exit(1); } hscrn = CreateScreen("WHEREIS v1.0", AUTO_DESTROY_SCREEN); SetCurrentScreen(hscrn); DisplayScreen(hscrn); strupr(strcpy(fid, argv[1])); printf("WHEREIS: %s...\n",fid); dowhereis(fid); PressAnyKeyToContinue(); return(0); } void dowhereis(char *s) { char dir[_MAX_PATH]; char fsv[_MAX_SERVER+_MAX_VOLUME+1]; char fdir[_MAX_PATH]; char fname[_MAX_FNAME],fext[_MAX_EXT], both[_MAX_FNAME+_MAX_EXT]; char *p = next_arg(s); /* point at argument */ if(!*p) { printf("No filename specified!"); return; } strcpy(dir,GetWorkArea()); /* get the file name specification */ _splitpath(p,fsv,fdir,fname,fext); sprintf(both,"%s%s",strupr(fname),strupr(fext)); breakkey = FALSE; /* startup the recursive file find operation */ chdir(fsv); findit(both); } char *GetWorkArea(void) { static char cwd[_MAX_PATH]; static char serverName[_MAX_SERVER]; static char volumeName[_MAX_VOLUME + 1]; static char dirName[_MAX_DIR]; if(getcwd(cwd,_MAX_PATH) == NULL) return NULL; ParsePath(cwd,serverName,volumeName,dirName); /* shouldn’t fail! */ return cwd; } char *next_arg(char *s) { char *p; skipspace(s); /* ignore white */ p = s; nextspace(s); /* find next blank */ *s = NULL; return(p); } static void findit(char *what) { char dir[_MAX_PATH]; DIR *dirStructPtr; DIR *dirStructPtrSave; getcwd(dir,_MAX_PATH); dirStructPtrSave = dirStructPtr = opendir(what); while(dirStructPtr && !breakkey) { dirStructPtr = readdir(dirStructPtr); if((dirStructPtr == NULL) || (dirStructPtr == -1)) break; printf(" %s/%s\n",dir,dirStructPtr->d_name); if(kbhit() && getch() == 3) printf("^C\n",breakkey = TRUE); } if(dirStructPtrSave) closedir(dirStructPtrSave); /* Now traverse the directories in this path */ dirStructPtrSave = dirStructPtr = opendir("*.*"); if(dirStructPtr == NULL) return; while(!breakkey) { dirStructPtr = readdir(dirStructPtr); if((dirStructPtr == NULL) || (dirStructPtr == -1)) break; if(dirStructPtr->d_attr & _A_SUBDIR) { chdir(dirStructPtr->d_name); findit(what); chdir(".."); } if(kbhit() && getch() == 3) printf("^C\n",breakkey = TRUE); } if(dirStructPtrSave) closedir(dirStructPtrSave); }
NOTE: taken from NCPSCAN.C in the \EXAMPLES directory /********************************************************************* NCPSCAN.C ********************************************************************** This example demonstrates how to list registered NCP extensions using NWScanNCPExtensions (NLM). *********************************************************************/ #include <nlm/stdio.h> #include <nlm/stdlib.h> #include <nlm/nwncpx.h> int main(void) { BYTE majorVersion, minorVersion, revision; char NCPExtensionName[MAX_NCP_EXTENSION_NAME_BYTES]; int cCode; LONG NCPExtensionID = BEGIN_SCAN_NCP_EXTENSIONS; /* -1 */ do { cCode = NWScanNCPExtensions(&NCPExtensionID, NCPExtensionName, &majorVersion, &minorVersion, &revision, NULL); if(cCode == 0) { printf("\nExtension Name = %s, Extension ID = %lX", NCPExtensionName, NCPExtensionID); printf("\nMajor Version = %d, Minor Version = %d, Revision = %d\n", majorVersion, minorVersion, revision); } } while(cCode != -1); return(0); }
NOTE: taken from EXTATTRS.C in the \EXAMPLES directory /********************************************************************** EXTATTRS.C ********************************************************************** This example demonstrates how to manipulate the first attribute byte of an extended attribute. EXTATTRS.C uses the functions GetExtendedFileAttributes and SetExtendedFileAttributes. *********************************************************************/ #include <nlm/stdlib.h> #include <nlm/stdio.h> #include <nlm/nwfinfo.h> #include <nlm/nwfileio.h> int main(void) { char pn[300]; BYTE efa; printf("name: "); gets(pn); printf("efa: "); scanf("%x", &efa); printf("set rc = %d\r\n", SetExtendedFileAttributes(pn, efa)); printf("get rc = %d\r\n", GetExtendedFileAttributes(pn, &efa)); printf("new efa = %x\r\n", efa); return(0); }