isalpha()
toupper()
The nice thing about Visual C++ is that Microsoft has already written lots of code for you! For example, you don't have to write the code needed to copy a character string character by character. Visual C++ has done that for you in strcpy(). strcpy() is
one of several library functions that you've seen so far. Visual C++ provides several more library functions (often just called functions in this unit) that do work for you.
To use any library function, you need to include the proper header file and know the name of the function that you want to use and the type and number of parameters. For example, instead of writing the code needed to determine the length of a string,
you can include the STRING.H header file and request the strlen() function.
In addition to library functions, Visual C++ provides several library classes as well. You have used two library classescin and coutin just about every program in this book.
This unit teaches you several string, character, and numeric functions that do work for you. There are a lot more library functions included with Visual C++, but the ones described here are some of the most common.
The character functions let you change and test character variables for specific values.
This section explores many of the character functions available in Visual C++. Generally, you pass character arguments to the functions, and the functions return values that you can store or print. By using these functions, you offload much of your work
to Visual C++ and allow it to perform the more tedious manipulations of character and string data.
This book gives you a feel for the sort of functions you can expect to find in Visual C++. If there is some task for which you feel lots of programmers might need a function, look in the online help. Choose Help | C/C++ Language from the Visual C++
Workbench. The contents will point you to runtime library functions, and you can browse around looking for functions under the appropriate category.
Several functions test for certain characteristics of your character data. You can determine whether your character data is alphabetic, digital, uppercase, lowercase, and much more. You must pass a character variable or a literal argument to the
function (by placing the argument in the function parentheses) when you call it. These functions return a True or False result so that you can test their return values inside an if statement or a while loop.
All character functions presented in this section are prototyped in the CTYPE.H header file. Be sure to include CTYPE.H at the beginning of any programs that use these functions.
The following functions test for alphabetic conditions:
Remember that any nonzero value is True in Visual C++, and zero is always False. If you use the return values of these functions in a relational test, the True return value is not always 1 (it can be any nonzero value), but it is always considered True
for the test.
The following functions test for digits:
Although some character functions test for digits, the arguments are still character data and can't be used in mathematical calculations unless you calculate using the ASCII values of characters.
You can pass to these functions only a character value or an integer value holding the ASCII value of a character. You cannot pass an entire character array to character functions. If you want to test the elements of a character array, you must pass the array one element at a time.
A few character functions become useful when you have to read from a disk file, a modem, or another operating system device from which you route input. These functions are not used as much as the character functions you saw in the preceding section, but
they are useful for testing specific characters for readability. The character-testing functions do not change characters.
The remaining character-testing functions are as follows:
Some people program in Visual C++ for years and never need any of these functions. Programmers often use them to parse, or interpret, lines of input. Specialized applications such as language translators need special character-testing functions such as
these. Other times, a programmer produces a file that contains many control characters, and the programmer needs to strip out any data that is not a text or numeric character.
The two remaining character functions are handy. Rather than testing characters, these functions convert characters to their lowercase or uppercase equivalents.
These functions return their changed character values.
These functions are also useful for user input. Suppose that you ask users a yes-or-no question, such as the following:
Do you want to print the checks (Y/N)?
Before toupper() and tolower() were developed, you had to check for both a Y and a y to print the checks. Instead of testing for both conditions, you can convert the character to uppercase, and test for a Y.
Listing 23.1 contains a program that uses toupper() for character conversion.
The character testing and conversion functions give you the ability to check character data for certain conditions.
1:// Filename: GB.CPP 2:// Determines whether the user typed a G or a B. 3:#include <iostream.h> 4:// toupper is in ctype.h 5:#include <ctype.h> 6: 7:void main() 8:{ 9: char ans; // Holds user's response 10: 11: cout << "Are you a girl or a boy (G/B)? "; 12: cin >> ans; // Gets answer 13: 14: cout << endl; 15: 16: ans = toupper(ans); // Converts answer to uppercase 17: switch (ans) 18: { case ('G'): { cout << "You look pretty today!" << endl; 19: break; } 20: case ('B'): { cout << "You look handsome today!" << endl; 21: break; } 22: default : { cout << "Your answer makes no sense!" << endl; 23: break; } 24: } 25: return; 26:}
Output
Are you a girl or a boy (G/B)?b You look handsome today!
Analysis
Listing 23.1 prints an appropriate message if the user is a girl or a boy. The program tests for the uppercase G or B after converting the user's input to uppercase in line 16. No check for lowercase has to be done due to the toupper() function call.
As you have seen with the string and I/O functions throughout the book, you needed to add the appropriate header file, CTYPE.H, in line 5 to get the program to compile. When you use library functions, you do not include the entire body of the functions
in the compilation. Visual C++ keeps a ready-made collection of code in a library, and when the compiler moves on to the linking phase, it spots that you have used a library function and adds the extra bit of code needed by your program into the final
executable. The Options | Project | Linker controls the list of libraries Visual C++ uses, but normally you do not need to worry about this.
The string functions combine and check strings for certain conditions.
Some of the most powerful built-in Visual C++ functions are the string functions. They perform much of the tedious work for which you have been writing code so far, such as inputting strings from the keyboard and comparing strings.
As with the character functions, there is no need to reinvent the wheel by writing code, when built-in functions do the same task. Use these functions as much as possible.
Now that you have a good grasp of the foundations of Visual C++, you can master the string functions. They enable you to concentrate on your program's primary purpose rather than spend time coding your own string functions.
You can use a handful of useful string functions for string testing and conversion. In earlier lessons, you saw the strcpy() string function, which copies a string of characters to a character array.
All string functions in this section are prototyped in the STRING.H header file. Be sure to include STRING.H at the beginning of any program that uses the string functions.
The string functions work on string literals or on character arrays that contain strings.
The following are string functions that test or manipulate strings:
definition
To concatenate means to merge one string onto the end of another.
strcat(st1, " National");
The following code tests to see whether two strings (strings stored in character arrays) hold the same value:
if (!strcmp(s1, s2)) { cout << "They are the same"; }
This is a time when the NOT operator (!) is clear. Because strcmp() returns 0 or False if the strings compare, you must test for NOT False in order to perform the comparison and print if they truly do compare.
The following code stores the length of the string in n:
n = strlen("A string"); // Stores 8 in n
Before using strcat() to concatenate strings, use strlen() to ensure that the target string (the string being concatenated to) is large enough to hold both strings.
Sometimes you have to convert numbers stored in character strings to numeric data types. Visual C++ provides three functions that enable you to do this:
These three ato() functions are prototyped in the STDLIB.H header file. Be sure to include STDLIB.H at the beginning of any program that uses the ato() functions.
The string must contain a valid number. Here is a string that can be converted to an integer:
"1232"
The string must hold a string of digits short enough to fit in the target numeric data type. The following string could not be converted to an integer with the atoi() function:
"-1232495.654"
It could, however, be converted to a floating-point number with the atof() function.
Visual C++ can't perform any mathematical calculation with such strings, even if the strings contain digits that represent numbers. Therefore, you must convert any string to its numeric equivalent before performing arithmetic with it.
If you pass a string to an ato() function and the string does not contain a valid representation of a number, the ato() function returns 0.
The following code fragment gets a number from the user as a string and converts that string to a floating-point number:
float fv; // Will hold the converted number char cnum[20]; // Will hold the user's number cout << "How much was your check? "; cin >> cnum; // Gets the number into the character // array fv = atof(cnum); // Converts the string to a // floating-point
The conversion functions will become more useful to you after you learn about disk files in the last unit.
[ic: stop and type]Listing 23.2 contains a program that uses three string functions.
strcat(), strcmp(), strlen(), and the ato() functions give you added string power.
1:// Filename: STRPGM.CPP 2:// Program that uses string functions to 3:// work with string input 4:#include <iostream.h> 5:#include <string.h> 6:#include <stdlib.h> 7: 8:void main() 9:{ 10: char name[31]; 11: char age[4]; // Will hold a string of integer digits 12: int intAge; 13: 14: cout << "What is your name? "; 15: cin.getline(name, 30); 16: cout << "How old are you? "; 17: cin.getline(age, 3); 18: 19: // Make into one string if room for comma, space, and null 20: if ((strlen(name) + strlen(age) + 3) <= 30) 21: { 22: strcat(name, ", "); 23: strcat(name, age); 24: cout << "Your name and age: " << name << endl; 25: } 26: else 27: { // Here if name cannot hold entire string 28: cout << endl << "Thanks, " << name << endl; 29: } 30: 31: // Convert the age string to an integer 32: intAge = atoi(age); // Convert the age to an integer 33: intAge += 10; 34: cout << "In ten years, you'll be " << intAge << endl; 35: return; 36:}
Output
What is your name? Alan Reardon How old are you? 41 Your name and age: Alan Reardon In ten years, you'll be 51
Analysis
Notice that this program includes three header files in lines 4 through 6 to handle all the functions needed in the body of the code. Lines 15 and 17 accept string input from the user. Line 16's cout asks for an integer, but line 17 grabs the user's
response (the age) and stores the integer age in a character array as a zero-terminated string.
Line 20 checks to see whether there is enough room in name to hold both the name and the string age, separated by a comma and a space. Therefore, line 20's if determines whether name is long enough to hold the entire concatenated string. If so, line 22
appends a comma and a space to the name, and then line 23 appends the age string. Line 24 prints the results of the concatenated string.
If you don't check to see whether the target string is long enough to hold the fully concatenated string, Visual C++ will not issue an error but will overwrite an unprotected area of memory to complete the concatenation. The results of this overwriting of memory are unpredictable.
If there is not enough room to hold the entire concatenated string, line 28 prints a simple message that includes only the name.
Line 32 simply shows the atoi() function in action by converting the integer stored as a string to a numeric integer and placing that integer in the variable named intAge. Line 33 adds 10 to intAge just to show that intAge holds a numeric value.
Thank goodness for the numeric functions! With them, you can perform common calculations without having to write formulas or understand the internals of the math involved.
The following sections present many of the built-in Visual C++ numeric functions. As with the string functions, these functions convert and calculate numbers. They save you time because you don't have to write functions that do the same thing. Many of
these are trigonometric and advanced mathematical functions. You might use some of these numeric functions only rarely, but they are there if you need them.
These sections conclude the discussion of Visual C++'s standard built-in functions. As you develop more skills in Visual C++, you might find yourself relying on these I/O, string, character, and numeric functions when you write more powerful programs.
The following functions are available for trigonometric and logarithmic applications:
All mathematical and trigonometric functions are prototyped in the MATH.H header file. Be sure to include MATH.H at the beginning of any program that uses the numeric functions.
For many programmersespecially business programmersthese are probably the least-used Visual C++ functions because of the functions' highly technical nature.
Visual C++ supplies additional trigonometric functions, including hyperbolic equivalents of these three functions. Search the online help (via Help Topic Search within C/C++ Help from the help menu) for math functions to see all the Visual C++ mathematical functions.
If you are confused, you're probably in good company. Trigonometric functions are not used in everyday applications. If you don't have a need for them, leave them alone and you'll be just fine.
If you have to pass an angle that is expressed in degrees to these functions, convert the angle's degrees to radians by multiplying the degrees by pi/180.0. (pi equals approximately 3.14159.)
Several built-in numeric functions return results based on numeric variables and literals passed to them. Even if you write only a few science and engineering programs, some of these functions are useful. These numeric functions return double-precision
values. Here are the functions and their descriptions:
The following statement
cout << ceil(11.2);
prints 12 to the screen.
- fabs(x): Returns the absolute value of x. The absolute value of a number is its positive equivalent.
The following statement
cout << fabs(-412);
prints 412 to the screen.
Absolute value is used for distances (which are always positive), accuracy measurements, age differences, and other calculations that require a positive result.
You can find the nth root of any number by raising that number to the power of 1 divided by n. In other words, you could find the fourth root of 256 with this function call: fourth = pow(256, (1.0/4.0));
Listing 23.3 contains a program that uses fabs() to compute a difference between people's ages.
The mathematical and trigonometric functions give you lots of calculating power. By calling these functions by name, you eliminate a lot of code that you would normally have to write.
1:// Filename: ABS.CPP 2:// Computes the difference between two ages 3:#include <iostream.h> 4:#include <math.h> 5:void main() 6:{ 7: float age1, age2, diff; 8: cout << endl << "What is the first child's age? "; 9: cin >> age1; 10: cout << "What is the second child's age? "; 11: cin >> age2; 12: 13: // Calculates the positive difference 14: diff = age1 - age2; 15: diff = fabs(diff); // Determines the absolute value 16: 17: cout << endl << "They are " << diff << " years apart."; 18: return; 19:}
Output
What is the first child's age? 10 What is the second child's age? 12 They are 2 years apart.
Analysis
Due to the use of fabs() in line 15, the order of the ages doesn't matter. Without absolute value, this program would produce a negative age difference if the first age was less than the second. Because the ages are relatively small numbers,
floating-point variables are used in this example. Visual C++ automatically converts floating-point arguments to double precision when passing them to fabs(), although the compiler gently reminds you of the conversion back from double to float in case the
answer might be too big for a float.
Your programs can access the PC's internal clock and calendar through functions supplied by Visual C++.
The header file TIME.H includes necessary definitions for handling time and date values in your Visual C++ programs. There are two new data types that you should know when dealing with time and its types. They are
time_t
and
struct tm
time_t is defined in the TIME.H header file. Be sure to include TIME.H when you want to work with date or time functions. Although time_t is defined as nothing more than an unsigned long int, any variable you define with time_t, such as
time_t rightNow; // Defines a time variable
can hold a time value. In Visual C++, a time variable holds the number of seconds since midnight, January 1, 1970. That is when Visual C++ thinks that time began. Because you know the number of seconds, this is both a time and a date function. Depending
on how you calculate from those seconds, you can determine the proper time and even the date.
Consider the program that follows:
1:// Filename: TIME1.CPP 2:// Tests the time() function 3:#include <time.h> 4:#include <iostream.h> 5: 6:void main() 7:{ 8: time_t lt; 9: // Passing time() a NULL pointer makes it 10: // return the time in seconds 11: lt = time(NULL); // NULL is defined in stdio.h 12: cout << "The number of seconds since 1-1-1970: " << lt; 13: return; 14:} 15: 16: return; }
Here is the program's output:
The number of seconds since 1-1-1970: 804361926
You will get a different output depending on the time and date that you run the program.
Passing time() the NULL value (defined in STDIO.H) makes time() return a value, as shown in TIME1.CPP. You can then calculate from the seconds (by converting the seconds into hours, days, or months by dividing by the appropriate value) to get the date
or time needed. (Can you write a program to work out when I ran this example? Don't try yet!)
definition
The broken-down time structure is a special data value that holds time and date information.
Another time-related variable is a structure variable. The broken-down time structure variable is defined in the TIME.H header file, so be sure to include TIME.H when you work with the date or time.
You can access helpful values from the time structure with a function named localtime(). localtime() returns a pointer to a tm structure. Accessing a structure requires the pointer operator, just as you have seen with structures and classes.
Listing 23.4 contains a program that fills the broken-down time structure, letting the rest of the program access various elements of the date and time.
The TIME.H header file supplies several time and date access functions that you can use to work with the PC's time and date values.
1:// Filename: TIME2.CPP 2:// Printing date and time values 3:#include <iostream.h> 4:#include <time.h> 5: 6:void main() 7:{ 8: struct tm *local; // Pointer to the time structure 9: time_t t; 10: t = time(NULL); // Store seconds time in t 11: local = localtime(&t); // Fills the structure-pointed data 12: 13: cout << "The current seconds are " << local->tm_sec << endl; 14: cout << "The current minutes are " << local->tm_min << endl; 15: cout << "The current hours are " << local->tm_hour << endl; 16: cout << "The current day is " << local->tm_mday << endl; 17: cout << "The current month is " << local->tm_mon << endl; 18: cout << "The current year (since 1900) is " 19: << local->tm_year << endl; 20: cout << "The current weekday is " << local->tm_wday << endl; 21: cout << "The current day of year is " 22: << local->tm_yday << endl; 23: cout << "The current Daylight Savings Flag is " 24: << local->tm_isdst << endl; 25: // DST is 0 in during winter months, 1 otherwise 26: return; 27:}
Output
The current seconds are 34 The current minutes are 56 The current hours are 10 The current day is 28 The current month is 5 The current year (since 1900) is 95 The current weekday is 3 The current day of year is 178 The current Daylight Savings Flag is 1
Analysis
The program uses the time function to get the time from the system. Passing to time the localtime() function via a pointer returns the results of several time calculations into the tm structure. The sort of time required is then easily accessed from the
structure, as in line 13 for example.
When you are ready for a date or time value, look at TIME2.CPP, define the time variables as it does in lines 8 and 9, and call the time and localtime() functions. You can then print any of the remaining values or use them in your own calculations by
referencing them as this program does. See how powerful library functions are? How long would it take you to write a program to find out when I ran the earlier example now?
The real power of classes comes from class libraries, which save you from writing a lot of code.
So far, you have looked at library functions, but the world of C++ provides you with access to another set of prewritten codeclass libraries.
Standard C++ really only provides one set of classes for you to play withthe stream library of code. You've used these so often that you don't need to look through how to use them. The only thing that you have used with cin and cout that has not
been covered elsewhere are the << and >> operators. These are special operators that work a bit like an assignment operator, moving data from one side of the operator to another. Although the syntax looks a bit strange, there is nothing magic
about these provided classes. You can use them and derive from them yourself. In the next unit, you will work a lot with the file handling variations of the stream library.
You can buy libraries of classes that you can then use in your programs. There are classes to work with databases, draw graphs, and store large amounts of data easily in your programs.
The version of Visual C++ that you have with this book contains a very exciting class library called the Microsoft Foundation Class (MFC), which is an obscure way of saying that it is a library of classes for writing Windows programs. I hope
you're not too disappointed that we haven't done any Windows programming. There are a few reasons why we haven't tried to cover it: It has taken a whole book just to learn about programming in C++; you'll need another whole book to learn about how Windows
works and how to program in that. Any commercial Windows program developed now is likely to have been written at least in part using a class library, whether it is a commercially available class library or a manufacturer's own internal version. So there is
little point in trying to learn how to write Windows programs without using a class library.
Although it is interesting to write complicated programs, if you write the code, you have to sort out getting it to work and maintaining it as things change. In most professional environments, you need to write code quickly. A class library will most
likely have thousands of users who will have found any problems before you start to use the code. On PCs, complex class libraries often cost less than $200, which is often less than it costs a company to employ a programmer for one day. Programs that you
see on PCs today are more complicated than the ones around five years ago mainly because program writers are able to borrow code from previous versions. If the previous code was OOP, borrowing the code is very easy.
Class libraries are often supplied with source code, because you are encouraged to write new classes based on the provided classes. Although (hopefully) the documentation provided with the classes is good, when writing complex classes, you sometimes
need that extra information to see exactly how a class works. The most accurate documentation of a program is its source!
definition
API stands for Application Programming Interface, which is the set of function calls provided to allow users of a system to access it within a program.
As the last exercise in this unit, in Listing 23.5 you'll see a simple Windows program written using MFC. Don't expect to understand the program; just look to see how a class library is used to hide away the complications of Windows
programming and its thousands (literally) of API functions. The MFC comes with some extra goodies, one of which is the CString class.
To run this program, do not try to write it yourself. Use the project file provided so that the Workbench options are properly set. Do the following:
Choose Project | Open | MFC.MAK. This opens a project file that has lots of special options set and knows how to make windows programs. When you make the project, the Workbench uses the make file, rather than the default QuickWin settings, to decide how to build the project.
1:// File Name : MFC.CPP 2:// A very simple Windows program 3:// 4:// To compile and run this, you will need to 5:// use the MFC.MAK project included with the 6:// source. Choose Project | Open | MFC.MAK 7:// 8:#include<afxwin.h> // This lives in a different include 9: // directory 10: 11://------------------------------------------------------------ 12:// SimpleApp is a class that hides the Windows equivalent 13:// of main() 14:// 15:class SimpleApp:public CWinApp 16: { 17: public: 18: BOOL InitInstance() // A virtual function - trust me! 19: { 20: CString title("Hello World"); // A string class 21: title += "!"; // Classes can define operators too. 22: // Define the addition to concatenate 23: // a string. 24: // Make a window object with a frame border 25: CFrameWnd* mainWindow = new CFrameWnd; 26: // Tell Windows to make a window 27: mainWindow->Create(0,title); 28: // Assign the window to the application 29: m_pMainWnd = mainWindow; 30: // Tell Windows to show the window 31: m_pMainWnd->ShowWindow(m_nCmdShow); 32: // Tell Windows to make sure that the window 33: // is properly drawn. 34: m_pMainWnd->UpdateWindow(); 35: // Tell the base application that we successfully 36: // made a window 37: return TRUE; 38: } 39: 40: }; 41: 42: 43:SimpleApp SimpleApp; // This makes a global object 44: // which includes a main() 45: // that Windows can find
Output
Analysis
For a start, you are not expected to understand how the program really works because Windows programming is really quite complicated. But let's look through the listing and see what you can understand.
The code uses three library classes. The first is CWinApp, which is a Windows Application class (as is meant to be implied by the name). All MFC classes start with C for class. In line 15, to make a new Windows application, you derive a new class
SimpleApp from the provided CWinApp.
The second provided class that is very useful is the CString class. As you might expect, all programmers need better string handling functions than Visual C++ provides. Rather than everybody writing their own class, Microsoft has provided the CString
class. This not only manages storage, but adds a lot of useful extra features.
You can read about the CString member functions by pressing F1 with the edit cursor on the CString word in an edit window.
In line 20, a new CString object is created and initialized with a string. In line 21, the overridden += operator is used to provide string concatenation. Without the need for spare characters, allocating new memory, or length checks, you can easily add
character strings together by thinking of concatenation as string addition (you wouldn't want to add each character up).
In line 25, the third class is used. Without getting drowned in the details of MFC, you can create a frame window class that knows about the many lines of code and API calls needed to operate a Windows window. You first make an MFC frame window object
(line 25), ask MFC to make a Windows window (line 27), and then perform some other standard functions to show the window (lines 31 through 34). If you learn MFC, you need lessons on the correct calls to make things happen. It's a bit like learning to drive
a car: providing a gear shift and steering wheel does not mean you can drive it. For example, you won't find a matching delete for the new CFrameWnd, but the code is correct. You rely on MFC deleting the window for you.
How does the InitInstance function in line 18 get called? The magic is in the SimpleApp object declared in line 43. Hidden in the CWinApp class are all the function calls needed to start a Windows application. Somewhere in the heart of the class, when
starting the application, the base class calls the virtual function InitInstance(). As the call is virtual, it executes the object version, which you have overridden. This is a very important concept and it is just like using a class you derive yourself.
It means that a class written perhaps thousands of miles away from your PC knows how to call your code. A well-written library provides enough of these virtual functions so that in very place you might need to do your own processing, you can replace the
library code with your own.
When the application runs, notice that it does not run in the familiar QuickWin window but is a real application in its own right. It knows how to draw itself on the screen and put a title on the box, and you can resize it. It even has a system menu and
responds to the commands. What you are seeing is a combination of Windows code being called and class library code that asks Windows to create the application and work in a particular way. The few lines of code in your application are actually making use
of tens, if not thousands, of lines of code when it runs. Can you imagine how hard it would be to write a program that talked directly to the computer hardware to do the same as the few lines of code you have just written? This shows the power of OOP.
Although you can write libraries of code without using classes, managing functions without the aid of classes soon becomes difficult.
strcat(str1, str2);
isalpha(islower('s'));
cout << pow(64.0, (1.0/2.0)) ; cout << sqrt(64.0);
cout << floor(8.5) << " " << ceil(8.5);
// Filename: AD1.CPP #include <iostream.h> #include <ctype.h> void main() { if (isalpha('2')) { cout << "Yes"; } else { cout << "No"; } return; }
// Filename: AD2.CPP #include <iostream.h> #include <ctype.h> void main() { char ch = 'a'; if (islower(ch)) { cout << "Yes"; } else { cout << "No"; } return; }
// Filename: AD3.CPP #include <iostream.h> #include <ctype.h> void main() { char ch = 'a'; if (isupper(ch)) { cout << "Yes"; } else { cout << "No"; } return; }
// Filename: AD4.CPP #include <iostream.h> #include <ctype.h> void main() { char ch = 'a'; if (isdigit(ch)) { cout << "Yes"; } else { cout << "No"; } return; }
#include <ctype.h> #include <iostream.h> void main() { char first[30]; cout << "What is your first name? "; cin >> first; if (isalpha(first)) { cout << "Nice job, " << first << endl; } else { cout << "That is not a name!" << endl; } return; }
#include <string.h> #include <iostream.h> void main() { char full[10] = "\0"; // Will hold both names char first[10]; char last[10]; cout << "What is your first name? "; cin >> first; cout << "What is your last name? "; cin >> last; strcat(full, first); strcat(full, last); cout << "Your full name is " << full << endl; return; }
DRAWPUPILSLIPUPWARD
"Draw pupil's lip upward!" is a palindrome.