void
GMMIMEParser::ParseContentParameters
	(
	const JString&		text,
	JPtrArray<JString>*	strings
	)
{
	JString tmp = text;
	JString* str;
	JIndex findex;
	while (tmp.LocateSubstring("=", &findex) && findex > 1)
		{
		str = new JString(tmp.GetSubstring(1, findex - 1));
		assert(str != NULL);
		str->TrimWhitespace();
		str->ToLower();
		strings->Append(str);

		tmp.RemoveSubstring(1, findex);
		tmp.TrimWhitespace();

		// now we need to get the corresponding value.
		// we need to check for quotes first.
		JIndex index = 1;
		if (tmp.GetLength() > 1 && tmp.GetCharacter(1) == '\"')
			{
			FindStringEnd(tmp, &index);
			str = new JString(tmp.GetSubstring(2, index-1));
			assert(str != NULL);
			if (tmp.LocateSubstring(";", &findex))
				{
				tmp.RemoveSubstring(1, findex);
				}
			}
		else if (tmp.LocateSubstring(";", &index))
			{
			str = new JString();
			assert(str != NULL);
			if (index > 1)
				{
				*str = tmp.GetSubstring(1, index-1);
				}
			tmp.RemoveSubstring(1, index);
			}
		else
			{
			str = new JString(tmp);
			assert(str != NULL);
			}

		str->TrimWhitespace();
		strings->Append(str);

		tmp.TrimWhitespace();
		}
}
void
CMEditPrefsDialog::ChooseDebugger
	(
	const JCharacter*	name,
	JXInputField*		input
	)
{
	const JCharacter* map[] =
		{
		"name", name
		};
	const JString prompt = JGetString("ChooseDebuggerPrompt::CMEditPrefsDialog", map, sizeof(map));

	JString fullName;
	if ((JGetChooseSaveFile())->ChooseFile(prompt, "", &fullName))
		{
		JString text = input->GetText();
		JIndex i;
		if (text.LocateSubstring(" ", &i))
			{
			text.ReplaceSubstring(1, i-1, fullName);
			}
		else
			{
			text = fullName;
			}
		input->SetText(text);
		}
}
inline JBoolean
jTranslateRemoteToLocal1
	(
	const JCharacter*	host,
	const JString&		remotePath,
	const JCharacter*	mountDev,
	const JCharacter*	mountDir,
	JString*			localPath
	)
{
	const JString dev = mountDev;
	JIndex hostEndIndex;
	if (dev.LocateSubstring(":/", &hostEndIndex) && hostEndIndex > 1)
		{
		JString h = dev.GetSubstring(1, hostEndIndex-1);
		jGetFullHostName(&h);

		JString p = dev.GetSubstring(hostEndIndex+1, dev.GetLength());
		JAppendDirSeparator(&p);		// force complete name when check BeginsWith()

		if (host == h && remotePath.BeginsWith(p))
			{
			*localPath = remotePath;
			localPath->ReplaceSubstring(1, p.GetLength()-1, mountDir);
			JCleanPath(localPath);
			return kJTrue;
			}
		}

	return kJFalse;
}
JBoolean
JDirInfo::BuildRegexFromWildcardFilter
	(
	const JCharacter*	origFilterStr,
	JString*			regexStr
	)
{
	regexStr->Clear();

	JString filterStr = origFilterStr;
	filterStr.TrimWhitespace();

	if (filterStr.IsEmpty())
		{
		return kJFalse;
		}

	JIndex index;
	while (filterStr.LocateSubstring(" ", &index))
		{
		assert( index > 1 );
		const JString str = filterStr.GetSubstring(1, index-1);

		AppendRegex(str, regexStr);

		filterStr.RemoveSubstring(1, index);
		filterStr.TrimWhitespace();
		}

	assert( !filterStr.IsEmpty() );
	AppendRegex(filterStr, regexStr);
	return kJTrue;
}
void
XDLink::Send
	(
	const JCharacter* text
	)
{
	if (itsLink != NULL)
		{
		if (ProgramIsRunning())
			{
			StopProgram();
			}

		JString arg = " -i not_command";

		JString s = text;
		JIndex i;
		if (s.LocateSubstring("@i", &i))
			{
			s.ReplaceSubstring(i, i+1, arg);
			}
		else
			{
			s += arg;
			}

		SendRaw(s);
		}
}
void
XDLink::SendRaw
	(
	const JCharacter* text
	)
{
	if (itsLink != NULL)
		{
		JString s = text;
		s.TrimWhitespace();

		JIndex i;
		while (s.LocateSubstring("  ", &i))
			{
			s.ReplaceSubstring(i, i+1, " ");
			}

		itsLink->SendMessage(s);
		itsLink->StartTimer();

		if (!itsDebuggerBusyFlag)
			{
			itsDebuggerBusyFlag = kJTrue;
			Broadcast(DebuggerBusy());
			}

		Broadcast(DebugOutput(s, kCommandType));
		}
}
JOrderedSetT::CompareResult 	
GMessageHeader::CompareDates
	(
	GMessageHeader* const & h1,
	GMessageHeader* const & h2
	)
{
	int r = h1->GetYear() - h2->GetYear();
	if (r == 0)
		{
		if (h1->GetMonth() == h2->GetMonth())
			{
			r = h1->GetDay() - h2->GetDay();
			}
		else
			{
			JString month1 = h1->GetMonth();
			JString month2 = h2->GetMonth();
			JString months = "JanFebMarAprMayJunJulAugSepOctNovDec";
			JIndex val1;
			JIndex val2;
			if (months.LocateSubstring(month1, &val1) &&
				months.LocateSubstring(month2, &val2))
				{
				r = val1 - val2;
				}
			}
		}

	if (r == 0)
		{
		r = JStringCompare(h1->GetTime(), h2->GetTime(), kJFalse);
		}

	if (r > 0)
		{
		return JOrderedSetT::kFirstGreaterSecond;
		}
	else if (r < 0)
		{
		return JOrderedSetT::kFirstLessSecond;
		}
	else
		{
		return JOrderedSetT::kFirstEqualSecond;
		}
}
inline JBoolean
jTranslateLocalToRemote1
	(
	const JString&		localPath,
	const JCharacter*	mountDev,
	const JCharacter*	mountDir,
	JBoolean*			found,
	JString*			host,
	JString*			remotePath
	)
{
	if (!JIsSamePartition(localPath, mountDir))
		{
		return kJFalse;
		}

	const JString dev = mountDev;
	JIndex hostEndIndex;
	if (dev.LocateSubstring(":/", &hostEndIndex) && hostEndIndex > 1)
		{
		*host = dev.GetSubstring(1, hostEndIndex-1);

		#ifdef _J_CYGWIN
		if (host->GetLength() == 1 &&
			'A' <= host->GetFirstCharacter() && host->GetFirstCharacter() <= 'Z')
			{
			*host       = JGetHostName();
			*remotePath = localPath;
			JCleanPath(remotePath);
			*found = kJTrue;
			return kJTrue;
			}
		#endif

		jGetFullHostName(host);

		*remotePath = dev.GetSubstring(hostEndIndex+1, dev.GetLength());
		JAppendDirSeparator(remotePath);

		// use JIndexRange to allow empty

		JIndexRange r(strlen(mountDir)+1, localPath.GetLength());
		*remotePath += localPath.GetSubstring(r);
		JCleanPath(remotePath);

		*found = kJTrue;
		}

	return kJTrue;
}
JString
CMLineAddressTable::BuildAddress
	(
	const JString& addr
	)
{
	JString s = addr;
	JIndex i;
	if (s.LocateSubstring(" ", &i))
		{
		s.RemoveSubstring(i, s.GetLength());
		}

	s.Prepend("0x");
	return s;
}
inline void
jGetFullHostName
	(
	JString* host
	)
{
	if (!host->Contains("."))
		{
		const JString localhost = JGetHostName();
		JIndex dotIndex;
		if (localhost.LocateSubstring(".", &dotIndex))
			{
			*host += localhost.GetSubstring(dotIndex, localhost.GetLength());
			}
		}
}
void
GMMIMEParser::ParseContentDisposition
	(
	const JString&	val,
	GMIMEHeader*	header
	)
{
	// we first need to strip the type. this will be found before the
	// first ';' which will be followed by the parameters.
	JString tVal	= val;
	tVal.TrimWhitespace();
	JSize length	= tVal.GetLength();

	JIndex findex;
	if (tVal.LocateSubstring(";", &findex) && (findex > 1))
		{
		tVal.RemoveSubstring(1, findex);
		tVal.TrimWhitespace();
		}
	else
		{
		return;
		}

	JPtrArray<JString> strings(JPtrArrayT::kDeleteAll);
	ParseContentParameters(tVal, &strings);
	JSize count = strings.GetElementCount();
	for (JIndex i = 1; i <= count; i += 2)
		{
		JString* str = strings.NthElement(i);
		if ((*str == "filename") &&
			(strings.IndexValid(i+1)))
			{
			str	= strings.NthElement(i+1);
			if (str->LocateLastSubstring("/", &findex))
				{
				str->RemoveSubstring(1, findex);
				}
			if (str->LocateLastSubstring("\\", &findex))
				{
				str->RemoveSubstring(1, findex);
				}
			header->SetFileName(*str);
			}
		}
}
void
GFGLink::ParseClass
	(
	GFGClass* 		  list,
	const JCharacter* filename, 
	const JCharacter* classname
	)
{
	JBoolean ok	= kJTrue;
	if (itsCTagsProcess == NULL)
		{
		ok = StartCTags();
		}

	if (ok)
		{
		itsClassList	= list;
		itsCurrentClass	= classname;
		itsCurrentFile	= filename;

		JConvertToAbsolutePath(filename, "", &itsCurrentFile);

		itsCurrentFile.Print(*itsOutputLink);
		*itsOutputLink << std::endl;
		itsOutputLink->flush();

		JBoolean found = kJFalse;
		JString result = JReadUntil(itsInputFD, kDelimiter, &found);

		if (found)
			{
			JIndex findex;
			while (	result.LocateSubstring("\n", &findex) &&
					findex > 1)
				{
				JString line	= result.GetSubstring(1, findex - 1);
				result.RemoveSubstring(1, findex);
				ParseLine(line);
				}
			Broadcast(FileParsed());
			}
		}
}
void
GDBGetSourceFileList::HandleSuccess
	(
	const JString& origData
	)
{
	if (origData.BeginsWith("Source files for which symbols have been read in:"))
		{
		(JXGetApplication())->DisplayBusyCursor();

		JXFileListTable* table = (GetFileList())->GetTable();
		table->RemoveAllFiles();

		JString data = origData;
		JIndex i,j;
		while (data.LocateSubstring("Source files for which symbols", &i))
			{
			j = i;
			if (!data.LocateNextSubstring(":", &j))
				{
				j = data.GetLength();
				}
			data.ReplaceSubstring(i, j, ",");
			}
		data.TrimWhitespace();		// no comma after last file

		std::istrstream input(data.GetCString(), data.GetLength());
		JString fullName, path, name, s;
		JBoolean foundDelimiter;
		do
			{
			input >> ws;
			fullName = JReadUntil(input, ',', &foundDelimiter);
			fullName.TrimWhitespace();
			if (!fullName.IsEmpty())
				{
				JSplitPathAndName(fullName, &path, &name);
				table->AddFile(name);
				}
			}
			while (foundDelimiter);
		}
JBoolean
GAddressBookMgr::GetNextRecord
	(
	JString& line,
	JString& record,
	std::istream& is
	)
{
	if (line.IsEmpty())
		{
		return kJFalse;
		}
	JIndex index;
	if (line.LocateSubstring("\t", &index))
		{
		if (index > 1)
			{
			record = line.GetSubstring(1, index - 1);
			line.RemoveSubstring(1, index);
			return kJTrue;
			}
		line.RemoveSubstring(1, 1);
		return kJFalse;
		}
	record = line;
	if (record.Contains("(") && !record.Contains(")"))
		{
		JString temp = JReadUntil(is, ')');
		record += temp + ")";
		line = JReadLine(is);
		if (!line.IsEmpty() && (line.GetFirstCharacter() == '\t'))
			{
			line.RemoveSubstring(1, 1);
			}
		}
	else
		{
		line.Clear();
		}
	return kJTrue;
}
JBoolean
SplitClassNameAndArgs
	(
	const JString&	str,
	JString*		name,
	JString*		args
	)
{
	JIndex i;
	const JBoolean hasArgs = str.LocateSubstring("(", &i);
	if (hasArgs && 1 < i && i < str.GetLength())
		{
		*name = str.GetSubstring(1, i-1);
		*args = str.GetSubstring(i+1, str.GetLength());

		name->TrimWhitespace();
		args->TrimWhitespace();
		return kJTrue;
		}
	else if (hasArgs && i == 1)
		{
		cerr << "No class name in " << str << endl;
		name->Clear();
		args->Clear();
		return kJFalse;
		}
	else
		{
		if (hasArgs)
			{
			*name = str.GetSubstring(1, i-1);
			}
		else
			{
			*name = str;
			}
		name->TrimWhitespace();
		args->Clear();
		return kJTrue;
		}
}
void
GMMIMEParser::CleanParmValPair
	(
	const JString&	parmValPair,
	JString*		parm,
	JString*		val
	)
{
	JIndex findex;
	JBoolean ok	= parmValPair.LocateSubstring(":", &findex);
	JSize length	= parmValPair.GetLength();
	if (ok && (findex > 1) && (findex < length))
		{
		*parm	= parmValPair.GetSubstring(1, findex - 1);
		*val	= parmValPair.GetSubstring(findex + 1, length);

		JIndex index = 1;
		while (index <= val->GetLength())
			{
			JCharacter c = val->GetCharacter(index);
			if (c == '\"')
				{
				FindStringEnd(*val, &index);
				index++;
				}
			else if (c == '(')
				{
				Remove822Comment(val, index);
				}
			else
				{
				if (c == '\n')
					{
					val->SetCharacter(index, ' ');
					}
				index++;
				}
			}
		}
}
void
JFunctionWithVar::DrawString
	(
	const JExprRenderer&	renderer,
	const JCoordinate		left,
	const JCoordinate		midline,
	const JSize				fontSize,
	const JString&			str
	)
	const
{
	JCoordinate x = left;

	const JCharacter* greekPrefix = JPGetGreekCharPrefixString();
	const JSize greekPrefixLength = JPGetGreekCharPrefixLength();

	JString s = str;
	JIndex greekIndex;
	while (s.LocateSubstring(greekPrefix, &greekIndex) &&
		   greekIndex < s.GetLength() - greekPrefixLength + 1)
		{
		if (greekIndex > 1)
			{
			const JString s1 = s.GetSubstring(1, greekIndex-1);
			renderer.DrawString(x, midline, fontSize, s1);
			x += renderer.GetStringWidth(fontSize, s1);
			}

		const JCharacter c = s.GetCharacter(greekIndex + greekPrefixLength);
		renderer.DrawGreekCharacter(x, midline, fontSize, c);
		x += renderer.GetGreekCharWidth(fontSize, c);

		s.RemoveSubstring(1, greekIndex + greekPrefixLength);
		}

	if (!s.IsEmpty())
		{
		renderer.DrawString(x, midline, fontSize, s);
		}
}
JSize
JFunctionWithVar::GetStringWidth
	(
	const JExprRenderer&	renderer,
	const JSize				fontSize,
	const JString&			str
	)
	const
{
	JSize w = 0;

	const JCharacter* greekPrefix = JPGetGreekCharPrefixString();
	const JSize greekPrefixLength = JPGetGreekCharPrefixLength();

	JString s = str;
	JIndex greekIndex;
	while (s.LocateSubstring(greekPrefix, &greekIndex) &&
		   greekIndex < s.GetLength() - greekPrefixLength + 1)
		{
		if (greekIndex > 1)
			{
			const JString s1 = s.GetSubstring(1, greekIndex-1);
			w += renderer.GetStringWidth(fontSize, s1);
			}

		const JCharacter c = s.GetCharacter(greekIndex + greekPrefixLength);
		w += renderer.GetGreekCharWidth(fontSize, c);

		s.RemoveSubstring(1, greekIndex + greekPrefixLength);
		}

	if (!s.IsEmpty())
		{
		w += renderer.GetStringWidth(fontSize, s);
		}

	return w;
}
void
XDLink::SendMedicCommand
	(
	CMCommand* command
	)
{
	command->Starting();

	JString arg = " -i ";
	arg        += JString(command->GetTransactionID(), JString::kBase10);

	JString s = command->GetCommand();
	JIndex i;
	if (s.LocateSubstring("@i", &i))
		{
		s.ReplaceSubstring(i, i+1, arg);
		}
	else
		{
		s += arg;
		}

	SendRaw(s);
}
void
GMMIMEParser::ParseMIMEHeader
	(
	std::istream&		input,
	GMIMEHeader*	header,
	const JBoolean	display
	)
{
	JString data;
	JCharacter c	= input.peek();
	if (c == '\n')
		{
//		input.get(c);
		}
//	input >> std::ws;

	// first we need to search for the first empty line. This line is the
	// end of the header.

	JString line;
	while (1)
		{
		JBoolean found;
		line = JReadLine(input, &found);
		if (line.IsEmpty())
			{
			break;
			}
		if (isspace(line.GetFirstCharacter()))
			{
			line.TrimWhitespace();
			if (line.IsEmpty())
				{
				break;
				}
			data.AppendCharacter(' ');
			}
		else if (!data.IsEmpty())
			{
			data.AppendCharacter('\n');
			}
		data += line;
		}
	data.AppendCharacter('\n');

	// we now need to search through the header for parameter:value pairs
	// using the gmime_header_regex defined above.

	JArray<JIndexRange> ranges;
	gmime_header_regex.MatchAll(data, &ranges);

	JSize count = ranges.GetElementCount();
	for (JSize i = 1; i <= count; i++)
		{
		JIndexRange range = ranges.GetElement(i);
		JString parmValPair = data.GetSubstring(range);
		JString parm;
		JString val;
		if (parmValPair.BeginsWith("MIME") ||
			parmValPair.BeginsWith("Mime") ||
			parmValPair.BeginsWith("Content"))
			{
			CleanParmValPair(parmValPair, &parm, &val);
			parm.ToLower();
			if (parm == "mime-Version")
				{
				val.TrimWhitespace();
				header->SetVersion(val);
				}
			else if (parm == "content-type")
				{
				ParseContentType(val, header);
				}
			else if (parm == "content-transfer-encoding")
				{
				val.TrimWhitespace();
				val.ToLower();
				header->SetEncoding(val);
				}
			else if (parm == "content-disposition")
				{
				ParseContentDisposition(val, header);
				}
			}
		}

	// this is a nested message, so some of the headers need to be displayed
	if (display)
		{
		JString text = "---------\n";
		JIndex findex	= 1;
		if (data.BeginsWith("From: ") || data.LocateSubstring("\nFrom: ", &findex))
			{
			if (findex > 1)
				{
				findex ++;
				}
			JIndex eindex	= findex;
			if (data.LocateNextSubstring("\n", &eindex) && (eindex > findex + 1))
				{
				text += data.GetSubstring(findex, eindex - 1);
				text += "\n";
				}
			}
		findex	= 1;
		if (data.BeginsWith("Date: ") || data.LocateSubstring("\nDate: ", &findex))
			{
			if (findex > 1)
				{
				findex ++;
				}
			JIndex eindex	= findex;
			if (data.LocateNextSubstring("\n", &eindex) && (eindex > findex + 1))
				{
				text += data.GetSubstring(findex, eindex - 1);
				text += "\n";
				}
			}
		findex	= 1;
		const JCharacter* kSubjectStr	= "Subject: ";
		if (data.BeginsWith("Subject: ") || data.LocateSubstring("\nSubject: ", &findex))
			{
			if (findex > 1)
				{
				findex ++;
				}
			JIndex eindex	= findex;
			if (data.LocateNextSubstring("\n", &eindex) && (eindex > findex + 1))
				{
				text += data.GetSubstring(findex, eindex - 1);
				text += "\n";
				}
			}
		WriteTextString(&text, GMIMEHeader());
		}
}
void
JXTextMenuData::InsertMenuItems
	(
	const JIndex		startIndex,
	const JCharacter*	menuStr,
	const JCharacter*	idNamespace
	)
{
	JStringManager* strMgr = JGetStringManager();

	JSize currIndex = startIndex;
	JString str     = menuStr;
	JBoolean done   = kJFalse;
	JString itemText, shortcuts, nmShortcut, id, strID, id1;
	while (!done)
		{
		JIndex sepIndex;
		const JBoolean found = str.LocateSubstring("|", &sepIndex);
		if (found)
			{
			assert( sepIndex > 1 );
			itemText = str.GetSubstring(1, sepIndex-1);
			str.RemoveSubstring(1, sepIndex);
			}
		else
			{
			itemText = str;
			done     = kJTrue;
			}

		JBoolean isActive, hasSeparator, isCheckbox, isRadio;
		ParseMenuItemStr(&itemText, &isActive, &hasSeparator,
						 &isCheckbox, &isRadio, &shortcuts, &nmShortcut, &id);

		if (!JStringEmpty(idNamespace) && !id.IsEmpty())
			{
			strID  = id;
			strID += "::";
			strID += idNamespace;
			JString* itemText1;
			if (strMgr->GetElement(strID, &itemText1) && itemText1 != NULL)
				{
				itemText = *itemText1;
				JBoolean isActive1, hasSeparator1, isCheckbox1, isRadio1;
				ParseMenuItemStr(&itemText, &isActive1, &hasSeparator1,
								 &isCheckbox1, &isRadio1, &shortcuts, &nmShortcut, &id1);
				}
			}

		InsertItem(currIndex, itemText, isCheckbox, isRadio, shortcuts, nmShortcut, id);
		if (!isActive)
			{
			DisableItem(currIndex);
			}
		if (hasSeparator)
			{
			ShowSeparatorAfter(currIndex);
			}
		currIndex++;
		}
}
void
GMMIMEParser::ParseContentType
	(
	const JString&	val,
	GMIMEHeader*	header
	)
{
	// we first need to determine the type. this will be found before the
	// first '/' which will be followed by the subtype.
	JString tVal	= val;
	tVal.TrimWhitespace();
	JSize length	= tVal.GetLength();

	JString type;
	JIndex findex;
	if (tVal.LocateSubstring("/", &findex) && (findex > 1))
		{
		type = tVal.GetSubstring(1, findex - 1);
		tVal.RemoveSubstring(1, findex);
		tVal.TrimWhitespace();
		type.ToLower();
		header->SetType(type);
		}
	else
		{
		return;
		}

	// now we need to determine the subtype
	JString subType;
	length			= tVal.GetLength();
	JBoolean found	= kJFalse;
	JIndex index;
	if (tVal.LocateSubstring(";", &index))
		{
		subType = tVal.GetSubstring(1, index - 1);
		tVal.RemoveSubstring(1, index);
		}
	else
		{
		subType = tVal;
		tVal.Clear();
		}

	tVal.TrimWhitespace();
	subType.TrimWhitespace();
	subType.ToLower();
	header->SetSubType(subType);

	if (tVal.IsEmpty())
		{
		return;
		}

	JPtrArray<JString> strings(JPtrArrayT::kDeleteAll);
	ParseContentParameters(tVal, &strings);
	JSize count = strings.GetElementCount();
	for (JIndex i = 1; i <= count; i += 2)
		{
		JString* str	= strings.NthElement(i);
		if (type == kTextType)
			{
			if (*str == "charset")
				{
				if (strings.IndexValid(i+1))
					{
					str	= strings.NthElement(i+1);
					header->SetCharSet(*str);
					}
				}
			}
		else if (type == kMultipartType)
			{
			if (*str == "boundary")
				{
				if (strings.IndexValid(i+1))
					{
					str	= strings.NthElement(i+1);
					header->SetBoundary(*str);
					}
				}
			}
		if ((type == kAppType) ||
			(type == kImageType) ||
			(type == kTextType))
			{
			if (*str == "name")
				{
				if (strings.IndexValid(i+1))
					{
					str	= strings.NthElement(i+1);
					if (str->LocateLastSubstring("/", &findex))
						{
						str->RemoveSubstring(1, findex);
						}
					if (str->LocateLastSubstring("\\", &findex))
						{
						str->RemoveSubstring(1, findex);
						}
					header->SetFileName(*str);
					}
				}
			}
		}
}
Exemple #23
0
void
SMTPMessage::ReadReturnValue()
{
	JString line;
	JBoolean ok = itsLink->GetNextMessage(&line);
	assert(ok);

	if (itsCurrentMode != kDataHeader)
		{
		GMGetSMTPDebugDir()->AddText(line);
		}

	if ((itsCurrentMode != kStartUp) && (itsCurrentMode != kDataHeader))
		{
		JInteger value;
		JIndex findex;
		ok = line.LocateSubstring(" ", &findex);
		if (ok && (findex > 1))
			{
			JString number = line.GetSubstring(1, findex - 1);
			if (number.IsInteger())
				{
				number.ConvertToInteger(&value);
				}
			else
				{
				ok	= kJFalse;
				}
			}
		else
			{
			ok	= kJFalse;
			}

		if (!ok)
			{
			const JIndex kDashIndex	= 4;
			if (line.GetCharacter(kDashIndex) == '-')
				{
				// this is a multiline response.
				return;
				}
			}

		if (!ok || (value != kOKValue))
			{
			if (!itsIsTryingToQuit)
				{
				const JCharacter* map[] =
					{
					"err", line
					};
				const JString msg = JGetString("SMTPERROR", map, sizeof(map));

				JGetUserNotification()->ReportError(msg);
				}
			itsIsFinished = kJTrue;
			Broadcast(SendFailure());
			if (!itsIsTryingToQuit)
				{
				itsDeleteTask = new JXTimerTask(1000,kJTrue);
				assert( itsDeleteTask != NULL );
				itsDeleteTask->Start();
				ListenTo(itsDeleteTask);
				}
			return;
			}
		}

	if (itsCurrentMode < kTo)
		{
		itsCurrentMode++;
		}
	else if (itsCurrentMode == kTo)
		{
		if (itsCurrentIndex < itsToNames->GetElementCount())
			{
			itsCurrentIndex++;
			}
		else if (itsCcNames->GetElementCount() != 0)
			{
			itsCurrentMode = kCc;
			itsCurrentIndex = 1;
			}
		else if (itsBccNames->GetElementCount() != 0)
			{
			itsCurrentMode = kBcc;
			itsCurrentIndex = 1;
			}
		else
			{
			itsCurrentMode = kDataHeader;
			}
		}
	else if (itsCurrentMode == kCc)
		{
		if (itsCurrentIndex < itsCcNames->GetElementCount())
			{
			itsCurrentIndex++;
			}
		else if (itsBccNames->GetElementCount() != 0)
			{
			itsCurrentMode = kBcc;
			itsCurrentIndex = 1;
			}
		else
			{
			itsCurrentMode = kDataHeader;
			}
		}
	else if (itsCurrentMode == kBcc)
		{
		if (itsCurrentIndex < itsBccNames->GetElementCount())
			{
			itsCurrentIndex++;
			}
		else
			{
			itsCurrentMode = kDataHeader;
			}
		}
	else if (itsCurrentMode == kData)
		{
		itsIsFinished = kJTrue;
		Broadcast(MessageSent());
		GMGetSMTPDebugDir()->AddText("\n-------------------------------------\n");
		if (!itsIsTryingToQuit)
			{
			itsDeleteTask = new JXTimerTask(1000,kJTrue);
			assert( itsDeleteTask != NULL );
			itsDeleteTask->Start();
			ListenTo(itsDeleteTask);
			}
		return;
		}
	else
		{
		itsCurrentMode++;
		}

	SendNextData();
}
void
GFGLink::ParseInterface
	(
	GFGMemberFunction* 	fn,
	const JIndex 		line
	)
{
	std::ifstream is(itsCurrentFile);
	if (!is.good())
		{
		return;
		}

	// skip to the function's line
	JString str;
	for (JIndex i = 1; i < line; i++)
		{
		str	= JReadLine(is);
		}

	JSize p1	= JTellg(is);

	is >> std::ws;
	str	= JReadUntilws(is);
	if (str != "virtual")
		{
		return;
		}

	is >> std::ws;

	// return type
	str	= JReadUntilws(is);
	if (str	== "const")
		{
		str	+= " " + JReadUntilws(is);
		}
	fn->SetReturnType(str);

	is >> std::ws;

	// this should be the function name
	str	= JReadUntil(is, '(');
	str.TrimWhitespace();
	if (str != fn->GetFnName())
		{
		return;
		}

	// get arguments
	JCharacter delim	= ',';
	while (delim == ',')
		{
		JBoolean ok	= JReadUntil(is, 2, ",)", &str, &delim);
		if (!ok)
			{
			return;
			}
		JIndex findex;
		if (str.LocateSubstring("//", &findex))
			{
			JIndex eindex;
			if (str.LocateSubstring("\n", &eindex) &&
				eindex >= findex)
				{
				str.RemoveSubstring(findex, eindex);
				}
			}
		str.TrimWhitespace();
		if (!str.IsEmpty())
			{
			fn->AddArg(str);
			}		
		}

	is >> std::ws;

	// is it const;
	str	= JReadUntil(is, ';');
	if (str.Contains("const"))
		{
		fn->ShouldBeConst(kJTrue);
		}

	JSize p2	= JTellg(is);
	JSeekg(is, p1);

	str	= JRead(is, p2 - p1);
	fn->SetInterface(str);
}
int
main
	(
	int		argc,
	char*	argv[]
	)
{
	// find the configuration files

	if (!FindConfigFile(&classMapFile) ||
		!FindConfigFile(&optionMapFile) ||
		!FindConfigFile(&needFontListFile) ||
		!FindConfigFile(&needStringListFile) ||
		!FindConfigFile(&needCreateListFile))
		{
		return 1;
		}

	// parse the command line options

	JString inputName, codePath, stringPath, codeSuffix, headerSuffix;
	JString postCmd;
	JPtrArray<JString> userFormList(JPtrArrayT::kDeleteAll);	// empty => generate all forms
	JPtrArray<JString> backupList(JPtrArrayT::kDeleteAll);		// forms that have been backed up
	GetOptions(argc, argv, &inputName, &codePath, &stringPath,
			   &codeSuffix, &headerSuffix, &postCmd, &userFormList);

	// generate each requested form

	JBoolean changed = kJFalse;

	ifstream input(inputName);
	while (!input.eof() && !input.fail())
		{
		const JString line = JReadLine(input);
		if (line == kBeginFormLine)
			{
			// get form name

			JString formName = JReadLine(input);
			RemoveIdentifier(kFormNameMarker, &formName);

			// look for custom tag

			const JSize formNameLength = formName.GetLength();
			JString tagName            = kDefaultDelimTag;
			JString enclName;
			JIndex tagMarkerIndex;
			if (formName.LocateSubstring(kCustomTagMarker, &tagMarkerIndex) &&
				tagMarkerIndex <= formNameLength - kCustomTagMarkerLength)
				{
				tagName = formName.GetSubstring(
					tagMarkerIndex + kCustomTagMarkerLength, formNameLength);
				formName.RemoveSubstring(tagMarkerIndex, formNameLength);

				// get enclosure name

				const JSize tagNameLength = tagName.GetLength();
				JIndex enclMarkerIndex;
				if (tagName.LocateSubstring(kCustomTagMarker, &enclMarkerIndex) &&
					enclMarkerIndex <= tagNameLength - kCustomTagMarkerLength)
					{
					enclName = tagName.GetSubstring(
						enclMarkerIndex + kCustomTagMarkerLength, tagNameLength);
					tagName.RemoveSubstring(enclMarkerIndex, tagNameLength);
					}

				// report errors

				if (tagName != kDefaultDelimTag)
					{
					if (enclName.IsEmpty())
						{
						cerr << formName << ", " << tagName;
						cerr << ": no enclosure specified" << endl;
						}
					}
				else if (!enclName.IsEmpty() && enclName != kDefTopEnclVarName)
					{
					cerr << formName << ", " << tagName;
					cerr << ": not allowed to specify enclosure other than ";
					cerr << kDefTopEnclVarName << endl;
					}
				}

			if (ShouldGenerateForm(formName, userFormList))
				{
				GenerateForm(input, formName, tagName, enclName,
							 codePath, stringPath, codeSuffix, headerSuffix, &backupList);
				changed = kJTrue;
				}
			}
		}

	if (changed && !postCmd.IsEmpty())
		{
		const JError err = JExecute(postCmd, NULL);
		err.ReportIfError();
		}

	return 0;
}
JBoolean
JExpandHomeDirShortcut
	(
	const JCharacter*	path,
	JString*			result,
	JString*			homeDir,
	JSize*				homeLength
	)
{
	assert( !JStringEmpty(path) && result != NULL );

	JBoolean ok = kJTrue;
	if (path[0] == '~' && path[1] == '\0')
		{
		ok = JGetHomeDirectory(result);
		if (ok && homeDir != NULL)
			{
			*homeDir = *result;
			}
		if (ok && homeLength != NULL)
			{
			*homeLength = 1;
			}
		}
	else if (path[0] == '~' && path[1] == '/')
		{
		ok = JGetHomeDirectory(result);
		if (ok && homeDir != NULL)
			{
			*homeDir = *result;
			}
		if (ok && homeLength != NULL)
			{
			*homeLength = 2;
			}
		if (ok && path[2] != '\0')
			{
			*result = JCombinePathAndName(*result, path+2);
			}
		}
	else if (path[0] == '~')
		{
		JString userName = path+1;
		JIndex i;
		const JBoolean found = userName.LocateSubstring("/", &i);
		if (found)
			{
			userName.RemoveSubstring(i, userName.GetLength());
			}

		ok = JGetHomeDirectory(userName, result);
		if (ok && homeDir != NULL)
			{
			*homeDir = *result;
			}
		if (ok && homeLength != NULL)
			{
			*homeLength = found ? i+1 : strlen(path);
			}
		if (ok && found && path[i+1] != '\0')
			{
			*result = JCombinePathAndName(*result, path+i+1);
			}
		}
	else
		{
		*result = path;
		if (homeDir != NULL)
			{
			homeDir->Clear();
			}
		if (homeLength != NULL)
			{
			*homeLength = 0;
			}
		}

	if (ok)
		{
		return kJTrue;
		}
	else
		{
		result->Clear();
		if (homeDir != NULL)
			{
			homeDir->Clear();
			}
		if (homeLength != NULL)
			{
			*homeLength = 0;
			}
		return kJFalse;
		}
}