digitalmars.com                      
Last update Sun Mar 4 12:00:58 2018

IOstream

This chapter consists of: IOstream Classes and Functions has descriptions of the classes and functions.

C++, like C, has no built-in input or output statements. Instead, I/O facilities are provided by a library. The standard C++ I/O library is the iostream library.

As with much of object oriented programming, iostreams can be difficult to understand without reading through the material more than once. A terminology section defines many of the basic terms.

Predefined Iostreams

The four predefined iostreams are: The predefined iostreams are fully buffered, except for cerr. See the "Output Using Iostreams" and "Input Using Iostreams" sections.

Basic Structure of Iostream Interaction

The iostream library allows a program to use any number of input or output streams. Each stream has some source or sink, which might be one of the following:

A stream can be restricted to input or output, or a single stream can allow both input and output. The iostream library implements these streams using two processing layers.

Standard input and output are handled by special class objects derived from class istream or ostream.

The ifstream, ofstream, and fstream classes, which are derived from istream, ostream, and iostream respectively, handle input and output with files.

The istrstream, ostrstream, and strstream classes, which are derived from istream, ostream, and iostream respectively, handle input and output to and from arrays of characters.

When you want to open an input or output stream, you create an object of one of these types. You associate the streambuf member of the stream with a device or file. You generally do this association through the stream constructor, so you don't deal with the streambuf directly. The iostream library predefines stream objects for the standard input, standard output, and error output, so you don't have to create your own objects for those streams.

You use operators or iostream member functions to insert data into a stream (output) or extract data from a stream (input), and to control the format of data that you insert or extract.

To insert and extract a new data type (that is, one of your classes), you generally overload the insertion and extraction operators.

Iostream Terminology

The iostream libarary descriptions use the following terms, which are similar to terms from general programming but with specialized meanings.

buffer
A word with two meanings, one specific to the iostream package and one more generally applied to input and output.

When referring specifically to the iostream library, a buffer is an object of the type defined by the class streambuf.

A buffer, generally, is a block of memory used to make efficient transfer of characters for input or output. With buffered I/O, the actual transfer of characters is delayed until the buffer is full or forceably flushed.

This confusion allows such odd phrases as "an unbuffered buffer", which refers to a streambuf where there is no buffer in the first sense defined above. Because of this confusion, this chapter avoids use of the term buffer to refer to streambufs. However, the next chapter and other C++ documents use the term buffer to mean streambufs.

extraction
The process of taking input from an iostream.
fstream
An input or output stream for use with files.
insertion
The process of sending output into an iostream.
iostream
Generally, an input or output stream but can also refer to any of the classes in the iostream library.
Iostream library
The library implemented by header files iostream.h, fstream.h, strstream.h, iomanip.h, and stdiostream.h. Because iostream is an object-oriented library, you should extend it. So, some of what you can do with the iostream library is not implemented.
stream
An iostream, fstream, strstream, or user-defined stream.
streambuf
A buffer that contains a sequence of characters with a put or get pointer, or both. It refers generally to any object of class streambuf or a class derived from streambuf. Any stream object contains an object, or a pointer to an object, of a type derived from streambuf.
strstream
An iostream for use with character arrays.

Using Iostreams

To use iostream routines, include the header files for the part of the library needed. The header files are:

Header File Description
iostream.h Declares basic features of iostream library.
fstream.h Declares iostreams and streambufs specialized to files. Includes iostream.h.
strstream.h Declares iostreams and streambufs specialized to character arrays. Includes iostream.h.
iomanip.h Declares manipulators (values you insert into or extract from iostreams to have different effects).
fstream.h (obsolete) Declares iostreams and streambufs specialized to use stdio FILEs. Includes iostream.h.
stream.h (obsolete) For compatibility with old-style streams from C++ version 1.2. Includes iostream.h, fstream.h, iomanip.h, and stdiostream.h

Output Using Iostreams

Output using iostreams usually relies on the overloaded left shift operator (<<) which, in the context of iostream, is called the insertion operator. To send a value to standard output, insert the value in the predefined output stream cout and use the insertion operator. For example:

cout << someValue;
The insertion operator, overloaded for all built-in types, converts the value of someValue to its correct output representation. If, for example, someValue is a float value, the << operator converts the value to the correct sequence of digits and includes a decimal point. Where it inserts float values on the output stream, << is called the float inserter. In general, given a type X, << is called the X inserter. The format of output and how to control it is discussed in the "Format Control" section.

The iostream library does not know about user-defined types. If you define types for output, you must define an inserter (that is, overload the << operator) to handle them correctly.

The << operator may be applied repetitively. To insert two values on cout, use the statement:

cout << someValue << anotherValue;
Output shows no space between the two values. To include spaces in the output use the statement:

cout << someValue << " " << anotherValue;
The << operator has the precedence of the left shift operator (its built-in meaning). As with other operators, you can always use parentheses to guarantee the order of action. It is often a good idea to use parentheses to avoid problems of precedence. Of the following four statements, the first two are equivalent, but the last two are not.

cout << a + b; // + has higher precedence than <<
cout << (a + b);
cout << (a & y);// << has precedence higher than &
cout << a & y;// probably an error: (cout << a) & y

Defining Your Own Insertion Operator

The string class defined in the "Sample Program" section has this definition:
class string {
private:
   char* data;
   size_t size;

public:
   (functions not relevant here)

friend ostream& operator<<(ostream&,
       const string&);
friend istream& operator>>(istream&, string&);
};
The insertion and extraction operators in this case must be defined as friends because the data part of the string class is private. The definition of operator<< overloaded for use with strings is:

ostream& operator<< (ostream& ostr,
         const string& output)
{ return ostr << output. data;}
operator<< takes a reference to an ostream& as its first argument and returns the same ostream, making it possible to combine insertions in one statement:

cout << string1 << string2;

Handling Output Errors

Checking for errors when overloading operator<< is not necessary because the iostream library can propagate errors.

When an error occurs, the iostream where it occurred enters an error state. Bits in the iostream's state are set according to the general category of the error. The inserters defined in iostream ignore attempts to insert data into any stream that is in an error state, so such attempts do not change the iostream's state.

In general, the recommended way to handle errors is to check the state of the output stream periodically in some central place. If an error exists, you should handle it in some way. This chapter assumes that you define a function error, which takes a string and aborts the program. error is not a predefined function. See "Handling Input Errors" for an example of an error function. Examine the state of an iostream with the operator !, which will return a nonzero value if the iostream is in an error state. For example:

if (!cout)
   error("output error");
Another way to test for errors exists. The ios class defines operator void *() so it returns a NULL pointer when an error occurs. This allows you to use a statement like this:

if (cout << x)
   return; // return if successful
You can also use the function good, a member of ios:

if (cout.good() )
    return; // return if successful
The error bits are declared the definition of class ios in the enum:
enum io_state {goodbit = 0, eofbit = 1,
   failbit = 2, badbit = 4,
   hardfail = 0x80};

Flushing

As with most I/O libraries, iostream often accumulates output and sends it on in larger and generally more efficient chunks. To flush the buffer, simply insert the special value flush. For example:

cout << "Needs to get out immediately." << flush;
flush is a kind of object known as a manipulator, which is a value that may be inserted into an iostream to have some effect other than causing output of its value. It is really a function that takes an ostream& or istream& argument and returns its argument after performing some actions on it (see "Manipulators").

Binary Output

To obtain output in the raw binary form of a value, use the member function write as:

cout.write((char*)&x, sizeof(x));
This, however, violates type discipline by converting &x to char*. Doing so is normally harmless, but if the type of x is a class with pointers, virtual member functions, or one that requires nontrivial constructor actions, the value written by the above example cannot be read back in properly.

Input Using Iostreams

Input using iostream is similar to output. Use the extraction operator >> and string together extractions the way you can with insertions. For example to get two values from standard input:

cin >> a >> b ;
As with other overloaded operators, the extractors used depend on the types of a and b (and two different extractors are used if a and b have different types). The format of input and how you can control it is discussed in some detail in "Format Control". In general, though, leading whitespace characters (spaces, newlines, tabs, form-feeds, and so on) are ignored.

Defining Your Own Extraction Operators

When you want input for a new type, you overload the extraction operator for it, just as you overload the insertion operator for output.

Class string (shown in sections "Output Using Iostreams" and "Sample Program") defines its extraction operator like this:

istream& operator>> (istream& istr, string& input)
{
   const int maxline = 256;
   char holder[maxline];
   istr.get(holder, maxline, '\n');
   input = holder;
   return istr;
}
By convention, an extractor converts characters from its first argument (in this case, istream& istr), stores them in its second argument (always a reference) and returns its first argument. The second argument must be a reference because an extractor is meant to store the input value in its second argument.

The char* Extractor

This predefined extractor is mentioned here because it can cause problems. You use it like this:

char x[50];
cin >> x;
The extractor skips leading whitespace and extracts characters and copies them to x until it reaches another whitespace character. It then completes the string with a terminating null (0) character. Be careful because input can overflow the given array.

Reading Any Single Character

The char extractor skips whitespace, which can be a problem if your program needs to read the next character whether or not it is whitespace. To do this with either form of function get member:

char c;
cin.get(c); // leaves c unchanged if input fails

int b;
b = cin.get(); // sets b to EOF if input fails
To skip only blanks, stopping on a tab, newline, or any other character:

int a;
do {
    a = cin.get();
} while(a == ' ');

Binary Input

To read binary values (such as those written with the member function write), use the read member function. To input the raw binary form of x using the read member function, do the following, which is the inverse of the earlier example that used write.

cin.read((char*)&x, sizeof(x));

Peeking at Input

Use the peek member function to look at the next character in the stream without extracting it. For example:

if (cin.peek() != c)
  return 0;

Extracting Whitespace

By default, iostream extractors skip leading whitespace. You can turn off the skip flag to prevent this from happening. The following code turns off whitespace skipping from cin, then turns it on again.

cin.unsetf(ios::skipws); // turn off
...
cin.setf(ios::skipws, ios::skipws); // turn on
You can use the iostream manipulator ws to remove leading whitespace from the iostream, whether or not skipping is enabled. To remove the leading whitespace from iostream istr:
istr >> ws;

Handling Input Errors

By convention, an extractor whose first argument has a nonzero error state should not extract anything from the input stream and should not clear any error bits. An extractor that fails should set at least one error bit.

As with output errors, you should check the error state periodically and take some action (such as aborting) when you find a nonzero state. The ! operator returns the error state of an iostream. For example, the following code produces an input error if you type alphabetic characters for input:

#include <stream.h>
#include <stdlib.h>
void error (const char* message) {
 cout << message << "\n";
 exit(1);
}
main() {
 cout << "Enter some characters: ";
 int bad;
 cin >> bad;
 if (!cin)
   error("aborted due to input error");
 cout << "If you see this, not an error." << "\n";
 return 0;
}
Class ios has member functions that you can use for error handling. See the next chapter.

Using Iostreams with stdio

You can use stdio with C++ programs, but problems can occur when you mix iostreams and stdio in the same standard stream within a program. For example, if you write to both stdout and cout, independent buffering will occur; results might not be what you expect. The problem is worse if you input from both stdin and cin, since independent buffering can turn the input into trash.

To eliminate this problem with standard input, standard output, and standard error, use the following instruction before performing any input or output. It connects all the predefined iostreams with the corresponding predefined stdio FILEs.

ios::sync_with_stdio();
Such a connection is not the default because a significant performance penalty occurs when the predefined streams are made unbuffered as part of the connection. You can use both stdio and iostreams in the same program applied to different files with no difficulty. That is, you can write to stdout using stdio routines and write to other files attached to iostreams. You can open stdio FILEs for input and also read from cin so long as you do not also try to read from stdin.

Creating Iostreams

To read or write a stream other than the predefined iostreams, you must create your own iostream. In general that means creating objects of types defined in the iostream library. The following sections discuss the various types available.

Dealing with Files Using Class fstream

Dealing with files is similar to dealing with standard input and standard output; classes ifstream, ofstream, and fstream are derived from classes istream, ostream and iostream, respectively. As derived classes, they inherit the insertion and extraction operations (along with the other member functions) and also have members and constructors for use with files.

You must include the file fstream.h to use any of the fstreams. Use an ifstream when you only want to perform input, an ofstream for output only, and an fstream for a stream on which you want to perform both input and output. Use the name of the file as the constructor argument.

For example, to copy the file thisFile to the file thatFile:

ifstream fromFile("thisFile");
if (!fromFile)
 error("unable to open 'thisFile' for input");
ofstream toFile("thatFile");
if (!toFile)
 error("unable to open 'thatFile' for output");
char c;
while (toFile && fromFile.get(c))
  toFile.put(c);
This code: Note
You would not really copy a file this way, one character at a time. This code is provided only as an example of using fstreams. Instead, insert the streambuf associated with the input stream into the output stream.

Open Mode
The mode is constructed by or-ing bits from the enumerated type open_mode, which is an public type of class ios and has the definition:

enum open_mode
   {in= 1, out= 2, ate= 4, app= 8,
    trunc= 0x10, nocreate= 0x20,
    noreplace= 0x40};
You can open a file for both input and output. For example, the following code opens file someName for both input and output, attaching it to the fstream variable inoutFile.

fstream inoutFile("someName", ios::in | ios::out);
Declaring an fstream Without Specifying a File
You can declare an fstream without specifying a file and open the file later. For example, to create the ofstream toFile for writing.
ofstream toFile;
toFile.open(argv[1], ios::out);

Opening and Closing Files

You can close the fstream and then open it with another file. For example, to process a list of files provided on the command line:

ifstream infile;
for (char** f = &argv[1]; *f; ++f)
{
   infile.open(*f, ios::in);
   ...;
   infile.close();
}
Opening a File Using a File Descriptor
If you know a file descriptor (such as the integer 1 for standard output), you can open it like this:

ofstream outfile;
outfile.attach(1);
When opening a file by providing its name to one of the fstream constructors or by using the open function, the file automatically closes when the fstream is destroyed (by a delete or when it goes out of scope). When attaching a file to an fstream, it does not automatically close.

Repositioning Within a File

Several tools can alter the reading and writing position in a file.
streampos a type that records a position in an iostream.
tellg (tellp) an istream (ostream) member function that reports the file position. Since istream and ostream are the parent classes of fstream, tellg and tellp can also be invoked as a member function of the fstream class.
seekg (seekp) an istream (ostream) member function that finds a given position.
seek_dir enum that specifies relative positions for use with seek: enum seek_dir {beg = 0, cur = 1, end = 2 }
For example, given an fstream aFile:

// save current position
streampos original = aFile.tellp();
// reposition to end of file
aFile.seekp(0, ios::end);
// write a value to file
aFile << x;
// return to original position
aFile.seekp(original);
seekg (seekp) can take one or two parameters. When it has two parameters, the first is a position relative to the position indicated by the seek_dir value given as the second parameter. For example, to move 10 bytes from the end:

aFile.seekp(-10, ios::end);
To move 10 bytes forward from the current position:

aFile.seekp(10, ios::cur);
Note:
Arbitrary seeking on text streams is not portable.

Assigning Iostreams

Earlier versions of C++ allowed assignment of one stream to another. This is no longer allowed.

The problem with copying a stream object is that when two versions of the state information exist (such as a pointer to the current write point within an output file) each might be changed independently. This can cause problems. Copying stream objects is usually not necessary.

Format Control

Format control is described in the next chapter.

Manipulators

A manipulator is a value you can insert into or extract from iostreams to have special effects.

Because manipulators are ordinary identifiers, and therefore use up possible names, iostream does not define them for every possible function. Manipulators are listed and described in the next chapter.

To use predefined manipulators, include header file iomanip.h in your program.

You can define your own manipulators. The two basic kinds of manipulators are:

Plain Manipulators

A plain manipulator is a function that

  1. Takes a reference to a stream (takes an istream&, ostream&, or ios& argument).
  2. Operates on it in some way.
  3. Returns its argument.
The shift operators taking (a pointer to) such a function are predefined for iostreams, so the function may be put in a sequence of input or output operators. The shift operator calls the function rather than trying to read or write a value.

An example of a tab manipulator that inserts a tab in an ostream:

ostream& tab(ostream& os) {
        return os << '\t' ;
 }
...
cout << x << tab << y ;
This is an elaborate way to achieve what could be done with:

const char tab = '\t';
...
cout << x << tab << y;
Here is another example, which cannot be accomplished with a simple constant. Suppose you want to turn whitespace skipping on and off for an input stream. You can use separate calls to ios::setf and ios::unsetf to turn the skipws flag on and off, or you could define two manipulators:

ostream& skipon(istream &is) {
       is. setf(ios::skipws, ios::skipws);
       return is;
}

ostream& skipoff(istream& is) {
       is. unsetf(ios::skipws);
       return is;
}

 ...
cin >> skipon >> x >> skipoff >> y;

Parameterized Manipulators

A parameterized manipulator takes one or more parameters. It:

  1. Takes an istream&, ostream&, or ios& argument, one additional argument (the parameter).
  2. Operates on the stream.
  3. Returns its stream argument.
One of the parameterized manipulators in iomanip.h is setfill. setfill sets the character that fills out field widths. It is implemented as:

// file setfill.cpp
#include <iostream.h>
#include <iomanip.h>

// the private manipulator
static ios& sfill(ios& i, int f) {
     i.fill((char) f);
     return i;
}

// the public applicator
smanip_int setfill(int f) {
    return smanip_int(sfill, f);
}
A parameterized manipulator is implemeted in two parts:

The manipulator looks like any other manipulator, except it takes an extra parameter. In the previous code example, it takes an extra int parameter. You cannot place this manipulator function in a sequence of input or output operations, since no shift operator is defined for it. Instead, you must use an auxiliary function- the applicator.

The applicator calls the manipulator. The applicator is a global function, and you make a prototype for it available in a header file. Usually the manipulator is a static function in the file containing the source code for the applicator. The manipulator is called only by the applicator. If you make it static, its name stays out of the global address space.

Several classes are defined in the header file iomanip.h. Each class holds the address of a manipulator function and the value of one parameter. Iostream Library Class Descriptions describes iomanip classes. The previous example uses the smanip_int class, which works with an ios. Because it works with an ios, it also works with an istream and an ostream. The previous example also uses a second parameter of type int.

The applicator creates and returns a class object. In the previous code example the class object is an smanip_int, and it contains the manipulator and the int argument to the applicator. The iomanip.h file defines the shift operators for this class. When the applicator function setfill appears in a sequence of input or output operations, the applicator function is called, and it returns a class. The shift operator acts on the class to call the manipulator function with its parameter value, which was stored in the class.

In the next code example, the manipulator print_hex does the following:

  1. Puts the output stream into the hex mode.
  2. Inserts a long value into the stream.
  3. Restores the conversion mode of the stream.
The class omanip_long is used because this code example is for output only, and it operates on a long rather than an int.

static ostream& xfield(ostream& os, long v)
{
 long save = os.setf(ios::hex, ios::basefield);
 os << v;
 is.setf(save, ios::basefield);
 return s;
}

omanip_long print_hex(long v)
{
 return omanip_long(xfield, v);
}

strstreams: Iostreams for Arrays

See strstream in the next chapter.

stdiobufs: Iostreams for stdio FILEs

See stdiobuf in the next chapter.

Streambufs

Iostreams are the formatting part of a two-part (input or output) system. The other part of the system is made up of streambufs, which deal in input or output of unformatted streams of characters.

You usually use streambufs through iostreams, so you don't have to worry about the details of streambufs. You can use streambufs directly if you choose to, for example, if you need to improve efficiency or to get around the error handling or formatting built in to iostreams.

How Streambufs Work

A streambuf consists of a stream or sequence of characters and one or two pointers into that sequence. Each pointer points between two characters. (Pointers cannot actually point between characters, but it is helpful to think of them that way.)

A streambuf can have one or both of these pointers.

Position of Pointers
The positions of the pointers and the contents of the sequences can be manipulated in various ways. Whether or not both pointers move when manipulated depends on the kind of streambuf used. Generally, with queue-like streambufs, the get and put pointers move independently; with file-like streambufs the get and put pointers always move together. A strstream is an example of a queue-like stream; an fstream is an example of a file-like stream.

Using Streambufs

You never create an actual streambuf object, but only objects of classes derived from class streambuf. Examples are filebuf and strstreambuf, which are described in filebuf and ssbuf, in the next chapter. You can derive your own classes from streambuf, to provide an interface to a special device, or to provide other than basic buffering. sbuf. pub and sbuf. prot, in the next chapter, discuss how to do this.

Apart from creating your own special kind of streambuf, you might want to access the streambuf associated with an iostream to get at the public member functions. In addition, each iostream has a defined inserter and extractor that take a streambuf pointer. When a streambuf is inserted or extracted, the entire stream is copied.

Here is another way to copy a file, with the error checking omitted.

ifstream fromFile("thisFile");
ofstream toFile ("thatFile");
toFile << (streambuf*)fromFile.rdbuf();
Open the input and output files as before. Every iostream class has a member function rdbuf which returns a pointer to the streambuf object associated with it. In the case of an fstream, the streambuf object is type filebuf. Cast the filebuf* to a streambuf* so the appropriate inserter is called, and the entire file associated with fromFile is copied (inserted into) the file associated with toFile. The last line can also be written like this:

fromFile >> (streambuf*)toFile.rdbuf();
In this case, the source file is extracted into the destination. The two methods are equivalent.

Sample Program

Here is a sample C++ program. It has a ''toy'' implementation of a string class, and a small program to test it. The class is a ''toy'' because it is not full-featured, yet it shows a number of features a real class must have.

Header file

The header file str.h for the string class string is:
/* header file str.h for toy
   C++ strings package
*/
#include <string.h> /* for C string functions */
class ostream; /* to declare output of strings */

class string {
public:
  string();
  string(char *);
  void append(char *);
  const char* str() const;
  string operator+ (const string&) const;
  const string& operator=(const string&);
  const string& operator=(const char*);

private:
  char *data;
  size_t size;
};
inline string::string()
{ size = 0;
  data = NULL;
}
inline const char* string::str() const
{
  return data;
}
ostream& operator<<(ostream&, const string&);
istream& operator>>(istream&, string&);

Implementation file

The implementation file str.cpp of the string class functions is:
/* implementation of toy C++ string package */

#include <iostream.h>
#include "str.h"

string::string(char *aStr)
{
   if (aStr == NULL)
      size = 0;
   else
      size = strlen(aStr);

   if (size == 0)
      data = NULL;
   else {
      data = new char[size + 1];
      strcpy(data, aStr);
   }
}
void string::append(char *app)
{
 size_t appsize = app ? strlen(app) : 0;
 char *holder = new char[size + appsize + 1];

 if (size)
    strcpy(holder, data);
 else
    holder[0] = 0;

 if (app) {
    strcpy(&holder[size], app);
    size += appsize;
 }
 delete[] data;
 data = holder;
}
string string::operator+(
     const string& second) const
{
 string temp;
 temp.data = new char[size + second.size + 1]

 if (size)
    strcpy(temp.data, data);
 else
    temp.data[0] = 0;

 if (second.size)
   strcpy(&temp.data[size], second.data);
 temp.size = size + second.size;
 return temp;
}
const string& string::operator=(
        const string& second)
{
 if (this == &second)
    return *this; /* in case string = string */

 delete [] data;
 if (second.size) {
    data = new char[second.size+ 1];
    size = second.size;
    strcpy(data, second.data);
 }
 else {
    data = NULL;
    size = 0;
 }
 return *this;
}
const string& string::operator=(const char* str)
{
 delete[] data;

 if (str && str[0]) {
    size = strlen(str);
    data = new char[size + 1];
    strcpy(data, str);
 }
 else {
    data = NULL;
    size = 0;
 }
 return *this;
}
ostream& operator<< (
  ostream& ostr, const string& output)
{
 return ostr << output.data;
}
istream& operator>> (
  istream& istr, string& input)
{
 const int maxline = 256;
 char holder[maxline];
 istr.get(holder, maxline, '\n');
 input = holder;
 return istr;
}

Test file

The test file testr.cpp to test the string class is:
/* test code for toy C++ strings package */

#include <iostream.h>
#include "str.h"

int main()
{
 string first ("This is a string.");
 cout << "first: " << first <<"\n";

 string sec;
 sec = first;
 cout << "sec = first: " << sec << "\n";

 sec = "And this is another.";
 cout << "another sec: " << sec << "\n";

 cout <<" Type in a string .....";
 cin >> sec;
 cout << "sec: "<< sec << "\n"

 string third;
 third = sec+ first;
 cout << "sec + first: " << third << "\n";

 third = sec+ sec;
 cout << "sec + sec: " << third << "\n";

 third.append("plus");
 cout << "with append:" << third << "\n";

 third = third + sec;
 cout << "added to itself:" << third << "\n";

 return 0;
}

Compile and link the program

To compile and link the entire program use the command:
dmc -cpp -o testr testr.cpp str.cpp
Home | Compiler & Tools | IDDE Reference | STL | Search | Download | Forums