As a preface, I really do not want the exact solution to my problem, just guidance. I don't want you to give me the code. This isn't homework, it's just an exercise I'm trying to solve.
I just want you to tell me how to access VDU and directly change character on same screen.
The screen is divided into 25 rows and 80 columns. The characters that are displayed on the
screen are stored in a special memory called VDU memory (not to be confused with ordinary
memory). Each character displayed on the screen occupies two bytes in VDU memory.
The first of these bytes contains the ASCII value of the character being displayed, whereas, the second byte contains the colour in which the character is displayed. For example, the ASCII value of the character present on zeroth row and zeroth column on the screen is stored at location number 0xB8000000.
Therefore the colour of this character would be present at location number 0xB8000000 + 1. Similarly ASCII value of character in row 0, col 1 will be at location 0xB8000000 + 2, and its colour at 0xB8000000 + 3.
My task:
With this knowledge write a program which when executed would keep converting every capital letter on the screen to small case letter and every small case letter to capital letter. The procedure should stop the moment the user hits a key from the keyboard. This is an activity of a rampant Virus called Dancing Dolls. (For monochrome adapter, use 0xB0000000 instead of 0xB8000000).
Really I don't have any idea to build this code. I'm stuck at even getting started.
You are referring to what was once called the video refresh buffer. It's important to state that Dancing Dolls was a virus for DOS.
Basically, you are expecting video memory to be at address 0xB8000000 on your program's memory. However, modern Operating Systems (like Linux/Windows/Mac OS X) provide a virtual memory mechanism that prevents applications from manipulating devices directly. So the 0xB8000000 address your application sees is not the physical address 0xb8000000 that corresponds to the video refresh buffer. The last post of this thread also has some interesting info on this subject.
Nevertheless, the technique you are interested in is still valid for 16-bit DOS and is covered on the book Assembly Language Step-by-step: Programming with DOS and Linux. This book has a great section on chapter 6 that explains how this work exactly. The section is named Inspecting the Video Refresh Buffer with DEBUG, and has an interesting example that shows how to use debug.exe to access the video memory and modify it. I tested it successfully on cmd.exe of my Win 7 box.
But if you want to manipulate the screen of a Linux terminal, check ncurses:
It is a library of functions that manage an application's display on character-cell terminals
I think, most important is to be aware that your question is about an exercise that (apparently) at one time was designed to be easy and interesting.
However, that was long ago, and meanwhile both hardware and software has progressed. It is no longer easy to access physical memory. And, at least for the beginner, it is no longer interesting to do that.
Thus, the main goodness points of the exercise have been chopped off by time’s inexorable entropic action.
However, for one who absolutely want to do this exercise, that once-so-easily-accessible hardware can be simulated. Doing such a simulation transparently, so that the student code is the same as if it was for real, is rather difficult and system-dependent. However, if you (the student) just agree to explicitly call some “update” routine in order to simulate the hardware screen update, then it’s more near managable – and thus, old exercises can be reused! :-)
One can then imagine that main does some initialization of things, and calls a routine doTheDancingDolls with arguments that give access to simulated video memory, and the aforementioned “update” functionality:
void doTheDancingDolls(
curses::Console& console,
b8000::DisplayMemorySim& memorySim
)
{
do
{
// Whatever - this is where you Do Things to the simulated video memory.
// Then:
memorySim.update( console );
} while( !console.keyboard().keypressIsAvailable() );
console.keyboard().getKey(); // Consume the keypress.
}
… where the memorySim object somehow provides the necessary pointer to the simulated video memory – a pointer that corresponds to the B8000000 address in the exercise.
That’s the main idea, how to get a starting point for solving this exercise that's designed for now ANTIQUATED equipment.
Fleshing it out a bit more, here’s one possible implementation of the video memory simulation (note that this is not code that addresses the things that you were meant to do in the exercise, it just addresses the things that you were never meant to do, but possibly would have to today):
File [b8000.h]
#ifndef B8000_H
#define B8000_H
// A simulation of the early PC's 25*80 color text mode video memory.
// The structure of the memory is INTENTIONALLY not modelled in the
// exposed interface. A student can learn from imposing such structure.
//
// Copyright (c) 2011 Alf P. Steinbach.
//------------------------------------------ Dependencies:
#include "curses_plus_plus.h" // curses::Console
#include <vector> // std::vector
//------------------------------------------ Interface:
namespace b8000 {
typedef unsigned char Byte;
class DisplayMemorySim
{
private:
std::vector< Byte > buf_;
public:
enum { nColumns = 80, nLines = 25 };
DisplayMemorySim(): buf_( 2*nLines*nColumns ) {}
void* bufferPointer() { return &buf_[0]; }
void const* bufferPointer() const { return &buf_[0]; }
void update( curses::Console& console ) const
{
assert( console.nLines() >= nLines );
assert( console.nColumns() >= nColumns );
assert( console.colors().nColors() >= 16 );
for( int y = 0; y < nLines; ++y )
{
for( int x = 0; x < nColumns; ++x )
{
int const iCell = 2*(y*nColumns + x);
Byte const charCode = buf_[iCell];
Byte const colors = buf_[iCell + 1];
Byte const fg = colors & 0xF;
Byte const bg = colors >> 4;
console.colors().setFgBg( fg, bg );
console.putAt( x, y, charCode );
}
}
console.updateScreen();
}
};
} // namespace b8000
#endif
And the curses::Console class might be a simple wrapper over the curses library, e.g. like …
File [curses_plus_plus.h]
#ifndef CURSES_PLUS_PLUS_H
#define CURSES_PLUS_PLUS_H
// Sort of minimal C++ interface to the "curses" library.
// Copyright (c) 2011 Alf P. Steinbach.
//------------------------------------------ Dependencies:
#include "curses.h"
#if defined( _MSC_VER ) && defined( __PDCURSES__ )
# pragma comment( lib, "pdcurses.lib" )
#endif
#ifdef _MSC_VER
# pragma warning( disable: 4355 ) // 'this' used in member initializer
#endif
#include <assert.h> // assert
#include <stddef.h> // NULL
//------------------------------------------ Interface:
namespace curses {
class Console;
namespace detail {
template< class Number > inline Number square( Number x ) { return x*x; }
template< class Derived >
struct SingleInstance
{
static int& instanceCount()
{
static int n = 0;
return n;
}
SingleInstance( SingleInstance const& ); // No such.
SingleInstance& operator=( SingleInstance const& ); // No such.
SingleInstance()
{
++instanceCount();
assert(( "can only have one instance at a time", (instanceCount() == 1) ));
}
~SingleInstance() { --instanceCount(); }
};
} // namespace detail
namespace color {
#ifdef _WIN32 // Any Windows, 32-bit or 64-bit.
int const lightness = 0x08; // Windows only. 8
// The portable colors, expressed for Windows systems.
int const black = COLOR_BLACK; // 0
int const blue = COLOR_BLUE; // 1
int const green = COLOR_GREEN; // 2
int const cyan = COLOR_CYAN; // 3
int const red = COLOR_RED; // 4
int const magenta = COLOR_MAGENTA; // 5
int const yellow = COLOR_YELLOW | lightness; // 6 + 8
int const white = COLOR_WHITE | lightness; // 7 + 8
// Windows-specific colors.
int const gray = COLOR_BLACK | lightness;
int const lightBlue = COLOR_BLUE | lightness;
int const lightGreen = COLOR_GREEN | lightness;
int const lightCyan = COLOR_CYAN | lightness;
int const lightRed = COLOR_RED | lightness;
int const lightMagenta = COLOR_MAGENTA | lightness;
int const brown = COLOR_YELLOW & ~lightness; // A bit greenish.
int const lightGray = COLOR_WHITE & ~lightness;
#else
// The portable colors, expressed for non-Windows systems.
int const black = COLOR_BLACK;
int const blue = COLOR_BLUE;
int const green = COLOR_GREEN;
int const cyan = COLOR_CYAN;
int const red = COLOR_RED;
int const magenta = COLOR_MAGENTA;
int const yellow = COLOR_YELLOW;
int const white = COLOR_WHITE;
#endif
} // namespace color
class Colors
: private detail::SingleInstance< Colors >
{
private:
Colors( Colors const& ); // No such.
Colors& operator=( Colors const& ); // No such.
int n_;
int nPairs_;
int rawIndexOfPair0_;
int rawIndexFor( int fg, int bg ) const
{
return bg*n_ + fg;
}
public:
int nColors() const { return n_; }
int nColorPairs() const { return nPairs_; }
int indexFor( int fg, int bg ) const
{
int const rawIndex = rawIndexFor( fg, bg );
return 0?0
: (rawIndex == rawIndexOfPair0_)? 0
: (rawIndex == 0)? rawIndexOfPair0_
: rawIndex;
}
void setColorPair( int i )
{
::color_set( short( i ), NULL ); //attrset( COLOR_PAIR( i ) );
}
void setFgBg( int fg, int bg )
{
setColorPair( indexFor( fg, bg ) );
}
Colors( Console& )
{
::start_color(); // Initialize color support.
// Although these look like global constants, they're global variables
// that are initialized by the call to Curses' `start_color` (above).
n_ = ::COLORS; nPairs_ = ::COLOR_PAIRS;
assert( detail::square( n_ ) <= nPairs_ ); // Our requirement.
// Obtain curses' default colors, those are at color pair index 0.
{
short fg0 = -1;
short bg0 = -1;
::pair_content( 0, &fg0, &bg0 );
assert( fg0 != -1 );
assert( bg0 != -1 );
rawIndexOfPair0_ = rawIndexFor( fg0, bg0 );
}
// Initialize color pair table to support finding index for given colors.
// The color pair at index 0 can't be specified (according to docs),
// so trickery is required. Here like swapping index 0 to elsewhere.
for( int fg = 0; fg < n_; ++fg )
{
for( int bg = 0; bg < n_; ++bg )
{
int const i = indexFor( fg, bg );
if( i == 0 ) { continue; } // It's initialized already.
::init_pair( short( i ), short( fg ), short( bg ) );
}
}
}
};
class Keyboard
: private detail::SingleInstance< Keyboard >
{
private:
WINDOW* pCursesWin_;
bool isBlocking_;
int bufferedKeypress_;
bool hasBufferedKeypress_;
void setBlocking( bool desiredBlocking )
{
if( isBlocking_ != desiredBlocking )
{
::nodelay( pCursesWin_, !desiredBlocking );
isBlocking_ = desiredBlocking;
}
}
public:
int getKey()
{
if( hasBufferedKeypress_ )
{
hasBufferedKeypress_ = false;
return bufferedKeypress_;
}
setBlocking( true );
return ::getch();
}
bool keypressIsAvailable()
{
if( hasBufferedKeypress_ ) { return true; }
setBlocking( false );
int const key = ::getch();
if( key == ERR ) { return false; }
hasBufferedKeypress_ = true;
bufferedKeypress_ = key;
return true;
}
Keyboard( WINDOW& pCursesWin )
: pCursesWin_( &pCursesWin )
, isBlocking_( true )
, hasBufferedKeypress_( false )
{
::keypad( pCursesWin_, true ); // Assemble multi-character sequences into key symbols.
::nodelay( pCursesWin_, false );
assert( isBlocking_ == true );
}
~Keyboard()
{
setBlocking( true );
}
};
class Console
: private detail::SingleInstance< Console >
{
private:
::WINDOW* pCursesWin_;
Colors colors_;
Keyboard keyboard_;
Console( Console const& ); // No such.
Console& operator=( Console const& ); // No such.
static ::WINDOW* beginWin()
{
return ::initscr();
}
public:
// At least with pdcurses in Windows, these numbers are for the
// console window, i.e. not for its underlying text buffer.
int nColumns() const { return ::getmaxx( pCursesWin_ ); }
int nLines() const { return ::getmaxy( pCursesWin_ ); }
Colors& colors() { return colors_; }
Colors const& colors() const { return colors_; }
Keyboard& keyboard() { return keyboard_; }
Keyboard const& keyboard() const { return keyboard_; }
void putAt( int x, int y, char const s[] )
{
::mvaddstr( y, x, s );
}
void putAt( int x, int y, char c )
{
::mvaddch( y, x, c );
}
void updateScreen() { ::refresh(); }
Console()
: pCursesWin_( beginWin() )
, colors_( *this )
, keyboard_( *pCursesWin_ )
{
::cbreak(); // Immediate input (no line buffering).
::noecho(); // No input echo.
}
~Console()
{
::endwin();
}
};
} // namespace curses
#endif
To drive it all, in the main program you’d check whether the terminal window (Windows “ console window”) is sufficiently large, etc.:
File [main.cpp]
#include "string_util.h" // strUtil::S
#include "b8000.h" // b8000::DisplayMemorySim
#include "curses_plus_plus.h" // curses::Console
#include <algorithm> // std::max
#include <assert.h> // assert
#include <iostream> // std::cerr, std::endl
#include <stdexcept> // std::runtime_error, std::exception
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
void doTheDancingDolls(
curses::Console& console,
b8000::DisplayMemorySim& memorySim
)
{
do
{
// Whatever - this is where you Do Things to the simulated video memory.
// The following three lines are just to see that something's going on here.
using stringUtil::S;
static int x = 0;
console.putAt( 30, 5, S() << "I have now counted to " << ++x << "..." );
// Then:
//memorySim.update( console );
} while( !console.keyboard().keypressIsAvailable() );
console.keyboard().getKey(); // Consume the keypress.
}
bool throwX( std::string const& s ) { throw std::runtime_error( s ); }
void cppMain()
{
using std::max;
using stringUtil::S;
curses::Console console;
enum
{
w = b8000::DisplayMemorySim::nColumns,
h = b8000::DisplayMemorySim::nLines
};
(console.colors().nColors() >= 16)
|| throwX( "The console window doesn't support 16 colors." );
(console.nColumns() >= w)
|| throwX( S() << "The console window has less than " << w << " columns." );
(console.nLines() >= h)
|| throwX( S() << "The console window has less than " << h << " lines." );
namespace color = curses::color;
console.colors().setFgBg( color::lightRed, color::yellow );
console.putAt( 30, 0, " The Dancing Dolls! " );
console.putAt( 30, 1, S() << " In " << h << "x" << w << " color mode." );
console.putAt( 30, 3, S() << " Press ANY key to start... " );
console.keyboard().getKey();
console.putAt( 30, 3, S() << " Press ANY key to stop... " );
b8000::DisplayMemorySim displayMemorySim;
doTheDancingDolls( console, displayMemorySim );
}
int main()
{
using namespace std;
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
cout << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
This post got a bit long, so I’m not adding in the code for the S() thing (it's not much code but still).
Anyway, this should provide a starting point for experimentation.
Disclaimer: I just cobbled this together. It’s not very extensively tested. I may, for example, have misunderstood things about the curses library’ keyboard handling –. And I’m hoping that it will work also in *nix-land, but I don’t know.
Cheers & hth.,
#include<conio.h>
#include<dos.h>
#define MEMORY_SIZE 3999 // 2 bytes for each character total char 2000
void main(){
char far *vidmem = 0xB8000000; // video memory address row & column zero
int i,o=0;
for(i=0;i<=MEMORY_SIZE;i+=2){
if (o%2==0)
*( vidmem + i) = 'A';
else
*( vidmem + i) = 'a';
o++;
}
while(!kbhit()){
for(i=0;i<=MEMORY_SIZE;i+=2){
if(*( vidmem +i) == 'A')
*( vidmem + i) = 'a';
else
*( vidmem + i) = 'A';
}
delay(200); // wait for 200 ms
}
}
/* run and compile success fully in Turbo C++ v3.0 non error just warring during running programme u just want to disable it option>>compiler>>message>>portablity */
Are we talking about actually performing modifications to what is displayed on your screen or do we just take the above assignment as an exercise.
In the latter case it's just looping over the described memory region (0xb8000000 + 25 (rows) * 80 (columns) * 2(bytes/displayed char). Reading the char portion for each displayed character and converting it from upper/lower to lower/upper case.
Conversion is simply done by simple arithmetic. Look at http://www.asciitable.com/ :
E.g: A = 0x41, a = 0x61
So in order to convert one to the other just add/remove 0x20 from the read value.
Related
Say I have an ASCII encoded text file mytextfile.txt and I want to print it.
I have found various sources on MSDN, but none of it seems useful:
From here:
Defines a reusable object that sends output to a printer, when printing from a Windows Forms application.
public ref class PrintDocument : Component
However this is meant for C++ (not C)
I also found this, which defines several functions, none of which actually seem to have the ability to print:
IPrintDocumentPackageStatusEvent: Represents the progress of the print job.
IPrintDocumentPackageTarget: Allows users to enumerate the supported package target types and to create one with a given type ID. IPrintDocumentPackageTarget also supports the tracking of the package printing progress and cancelling.
IPrintDocumentPackageTargetFactory: Used with IPrintDocumentPackageTarget for starting a print job.
Ah! That looks like it! Well it turns out that this is also for C++:
IPrintDocumentPackageTargetFactory::CreateDocumentPackageTargetForPrintJob
I think it is impracticle (and difficult) to try and imitate classes in C.
I could use the print command:
system("print mytextfile.txt");
But this does seem to be a bit of a hack, is there a better way to print a file using functions?
To clarify: I want this printing on paper not in terminal.
Here is some sample printing code for you that should do the job properly. It is a minimal, self-contained example that you should be able to just compile and run. Based on that, you should then be able to adapt it to your specific needs. First, here's the code, and then some explanatory notes.
Please note that I have written this as a Console app, but that's probably not what you actually want. Also, the function that does all the work (print_file()) is now callable from C as requested. OK, here's the code:
#include <windows.h>
#include <conio.h>
#include <string>
#include <fstream>
#include <iostream>
#define SCALE_FACTOR 100 // percent
inline static int MM_TO_PIXELS (int mm, int dpi)
{
return MulDiv (mm * 100, dpi, 2540);
}
// Calculate the wrapped height of a string
static int calculate_wrapped_string_height (HDC hDC, int width, const std::string& s)
{
RECT r = { 0, 0, width, 16384 };
DrawText (hDC, s.c_str (), (int) s.length (), &r, DT_CALCRECT | DT_NOPREFIX | DT_WORDBREAK);
return (r.bottom == 16384) ? calculate_wrapped_string_height (hDC, width, " ") : r.bottom;
}
// Print a string in the width provided.
static void print_string (HDC hDC, int x, int y, int width, const std::string& s)
{
RECT r = { x, y, x + width, 16384 };
DrawText (hDC, s.c_str (), (int) s.length (), &r, DT_NOPREFIX | DT_WORDBREAK);
}
// Print page number. Returns (y + vertical space consumed)
static int print_pagenum (HDC hDC, int x, int y, int width, int& pagenum)
{
std::string hdr = "Page: " + std::to_string (++pagenum) + "\n";
int space_needed = calculate_wrapped_string_height (hDC, width, hdr);
print_string (hDC, x, y, width, hdr);
std::cout << "Printing page: " << pagenum << "\n";
return space_needed;
}
extern "C" bool print_file (const char *filename)
{
std::ifstream f;
f.open ("g:\\temp\\print_me.txt", std::ios_base::in);
if (!f)
{
std::cout << "Cannot open input file, error " << GetLastError () << "\n";
return false;
}
// Display print dialog
PRINTDLGEX pdex = { sizeof (pdex) };
PRINTPAGERANGE pr [10] = { };
HDC hDC;
pdex.hwndOwner = GetDesktopWindow ();
pdex.Flags = PD_ALLPAGES | PD_RETURNDC | PD_NOCURRENTPAGE | PD_NOSELECTION;
pdex.nMaxPageRanges = _countof (pr);
pdex.nPageRanges = 1;
pr [0].nFromPage = pr [0].nToPage = 1;
pdex.lpPageRanges = pr;
pdex.nMinPage = 1;
pdex.nMaxPage = 999999;
pdex.nCopies = 1;
pdex.nStartPage = START_PAGE_GENERAL;
HRESULT hr = PrintDlgEx (&pdex);
if (hr != S_OK)
{
std::cout << "PrintDlgEx failed, error " << GetLastError () << "\n";
return false;
}
if (pdex.dwResultAction == PD_RESULT_CANCEL)
return false;
hDC = pdex.hDC;
if (pdex.dwResultAction != PD_RESULT_PRINT)
{
DeleteDC (hDC);
return false;
}
// Only print what we need to
int max_page = 0x7fffffff;
if (pdex.Flags & PD_PAGENUMS)
{
max_page = 0;
for (int i = 0; i < (int) pdex.nPageRanges; ++i)
{
if ((int) pdex.lpPageRanges [i].nToPage > max_page)
max_page = pdex.lpPageRanges [i].nToPage;
}
}
constexpr int dpi = 96 * 100 / SCALE_FACTOR;
int lpx = GetDeviceCaps (hDC, LOGPIXELSX);
int lpy = GetDeviceCaps (hDC, LOGPIXELSX);
int res_x = GetDeviceCaps (hDC, HORZRES);
int res_y = GetDeviceCaps (hDC, VERTRES);
// margins
int left_margin = MM_TO_PIXELS (10, dpi);
int top_margin = MM_TO_PIXELS (20, dpi);
int right_margin = MM_TO_PIXELS (20, dpi);
int bottom_margin = MM_TO_PIXELS (20, dpi);
int width = MulDiv (res_x, dpi, lpx) - (left_margin + right_margin);
int y_max = MulDiv (res_y, dpi, lpy) - bottom_margin;
// Set up for SCALE_FACTOR
SetMapMode (hDC, MM_ANISOTROPIC);
SetWindowExtEx (hDC, dpi, dpi, NULL);
SetViewportExtEx (hDC, lpx, lpy, NULL);
SetStretchBltMode (hDC, HALFTONE);
DOCINFO di = { 0 };
di.cbSize = sizeof (di);
di.lpszDocName = "Stack Overflow";
int job_id = StartDoc (hDC, &di);
if (job_id <= 0)
{
std::cout << "StartDoc failed, error " << GetLastError () << "\n";
DeleteDC (hDC);
return false;
}
SetBkMode (hDC, TRANSPARENT);
LOGFONT lf = { 0 };
lf.lfWeight = FW_NORMAL;
lf.lfHeight = -12;
HFONT hTextFont = CreateFontIndirect (&lf);
HFONT hOldFont = (HFONT) GetCurrentObject (hDC, OBJ_FONT);
SelectObject (hDC, hTextFont);
int x = left_margin;
int y = top_margin;
int pagenum = 0;
int err = StartPage (hDC);
if (err <= 0)
{
std::cout << "StartPage failed, error " << GetLastError () << "\n";
DeleteDC (hDC);
return false;
}
y += print_pagenum (hDC, x, y, width, pagenum);
// Printing loop, per line
for ( ; ; )
{
if (_kbhit ())
{
AbortDoc (hDC);
break;
}
std::string line;
std::getline (f, line);
if (!f)
break;
int space_needed = calculate_wrapped_string_height (hDC, width, line);
if (space_needed > y_max - y)
{
if (pagenum >= max_page)
break;
if (EndPage (hDC) < 0 || StartPage (hDC) < 0)
break;
y = top_margin;
y += print_pagenum (hDC, x, y, width, pagenum);
}
print_string (hDC, x, y, width, line);
y += space_needed;
}
EndPage (hDC);
EndDoc (hDC);
SelectObject (hDC, hOldFont);
DeleteObject (hTextFont);
DeleteDC (hDC);
return true;
}
// main
int main ()
{
bool ok = print_file ("g:\\temp\\print_me.txt");
return !ok;
}
Notes:
The code shows how to paginate the output properly. I included page numbers in he printed output, just for fun.
Input filename is hard-coded. Please adapt this to your needs.
As I say, this is written as a Console app. If you were including this in a Windows app you would use a different parent window handle and a different mechanism (a modeless dialog, typically) to report progress and to allow the user to cancel the print job.
The code as written expects to be compiled as ANSI (purely for convenience). I'm sure you can fix that.
This code doesn't handle page ranges entered by the user in the Windows standard Print dialog properly. I leave that as an exercise for the reader.
To make this code callable from C, compile it as a separate .cpp file (excluding main of course) and then prototype print_file (in a
separate .h file) as:
extern "C" bool print_file (const char *filename);
Then #include this file in both your .cpp file and your .c file (s).
Please note that bool is a predefined type - sort of - in C99 and later, see:
https://stackoverflow.com/a/1608350/5743288
You could read a line, print a line, in a loop, until EOF
Following EDITED to output to printer
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUF_SIZE 1024
int main( void )
{
char buffer[ MAX_BUF_SIZE ];
FILE *fin = fopen( "mytextfile.txt", "f" );
if( ! fin )
{
perror( "fopen failed for reading file" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
FILE *printer = fopen("LPT1", "w");
if( !printer )
{
perror( "fopen failed for printing" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
while( fgets( buffer, sizeof buffer, fin ) )
{
fprintf( printer, "%s", buffer );
}
fprintf( printer, "%s", "\n" );
fclose( fin );
fclose( printer );
return 0;
}
I made this state machine :
enum states { STATE_ENTRY, STATE_....} current_state;
enum events { EVENT_OK, EVENT_FAIL,EVENT_REPEAT, MAX_EVENTS } event;
void (*const state_table [MAX_STATES][MAX_EVENTS]) (void) = {
{ action_entry , action_entry_fail , action_entry_repeat }, /*
procedures for state 1 */
......}
void main (void){
event = get_new_event (); /* get the next event to process */
if (((event >= 0) && (event < MAX_EVENTS))
&& ((current_state >= 0) && (current_state < MAX_STATES))) {
state_table [current_state][event] (); /* call the action procedure */
printf("OK 0");
} else {
/* invalid event/state - handle appropriately */
}
}
When I modify a global variable in one state the global variable remain the same , and I need that variable in all the states . Do you now what could be the problem ?
My Global variable is this structure:
#if (CPU_TYPE == CPU_TYPE_32)
typedef uint32_t word;
#define word_length 32
typedef struct BigNumber {
word words[64];
} BigNumber;
#elif (CPU_TYPE == CPU_TYPE_16)
typedef uint16_t word;
#define word_length 16
typedef struct BigNumber {
word words[128];
} BigNumber;
#else
#error Unsupported CPU_TYPE
#endif
BigNumber number1 , number2;
Here is how I modify:
//iterator is a number from where I start to modify,
//I already modified on the same way up to the iterator
for(i=iterator+1;i<32;i++){
nr_rand1=661;
nr_rand2=1601;
nr_rand3=1873;
number2.words[i]=(nr_rand1<<21) | (nr_rand2<<11) | (nr_rand3);
}
This is just in case you may want to change your approach for defining the FSM. I'll show you with an example; say you have the following FSM:
You may represent it as:
void function process() {
fsm {
fsmSTATE(S) {
/* do your entry actions heare */
event = getevent();
/* do you actions here */
if (event.char == 'a') fsmGOTO(A);
else fsmGOTO(E);
}
fsmSTATE(A) {
event = getevent();
if (event.char == 'b' || event.char == 'B') fsmGOTO(B);
else fsmGOTO(E);
}
fsmSTATE(B) {
event = getevent();
if (event.char == 'a' ) fsmGOTO(A);
else fsmGOTO(E);
}
fsmSTATE(E) {
/* done with the FSM. Bye bye! */
}
}
}
I do claim (but I believe someone will disagree) that this is simpler, much more readable and directly conveys the structure of the FSM than using a table. Even if I didn't put the image, drawing the FSM diagram would be rather easy.
To get this you just have to define the fsmXXX stuff as follows:
#define fsm
#define fsmGOTO(x) goto fsm_state_##x
#define fsmSTATE(x) fsm_state_##x :
Regarding the code that changese number2:
for(i=iterator+1;i<32;i){
nr_rand1=661;
nr_rand2=1601;
nr_rand3=1873;
number2.words[i]=(nr_rand1<<21) | (nr_rand2<<11) | (nr_rand3);
}
I can't fail to note that:
i is never incremented, so just one element of the array is changed (iterator+1) over an infinite loop;
even if i would be incremented, only the a portion of the words array it's changed depending on the value of iterator (but this might be the intended behaviour).
unless iterator can be -1, the element words[0] is never changed (again this could be the intended behaviour).
I would check if this is really what you intended to do.
If you're sure that it's just a visibility problem (since you said that when you declare it as local it worked as expected), the only other thing that I can think of is that you have the functions in one file and the main (or where you do your checks) in another.
Then you include the same .h header in both files and you end up (due to the linker you're using) with two different number2 because you did not declare it as extern in one of the two files.
Your compiler (or, better, the linker) should have (at least) warned you about this, did you check the compilation messages?
This is not an answer - rather it is a comment. But it is too big to fit the comment field so I post it here for now.
The code posted in the question is not sufficient to find the root cause. You need to post a minimal but complete example that shows the problem.
Something like:
#include<stdio.h>
#include<stdlib.h>
#include <stdint.h>
typedef uint32_t word;
#define word_length 32
typedef struct BigNumber {
word words[4];
} BigNumber;
BigNumber number2;
enum states { STATE_0, STATE_1} current_state;
enum events { EVENT_A, EVENT_B } event;
void f1(void)
{
int i;
current_state = STATE_1;
for (i=0; i<4; ++i) number2.words[i] = i;
}
void f2(void)
{
int i;
current_state = STATE_0;
for (i=0; i<4; ++i) number2.words[i] = 42 + i*i;
}
void (*const state_table [2][2]) (void) =
{
{ f1 , f1 },
{ f2 , f2 }
};
int main (void){
current_state = STATE_0;
event = EVENT_A;
state_table [current_state][event] (); /* call the action procedure */
printf("%u %u %u %u\n", number2.words[0], number2.words[1], number2.words[2], number2.words[3]);
event = EVENT_B;
state_table [current_state][event] (); /* call the action procedure */
printf("%u %u %u %u\n", number2.words[0], number2.words[1], number2.words[2], number2.words[3]);
return 0;
}
The above can be considered minimal and complete. Now update this code with a few of your own functions and post that as the question (if it still fails).
My code doesn't fail.
Output:
0 1 2 3
42 43 46 51
I want to configure (module A) to send certain data to (module B) at certain slots of time.
(Module B) should send these configuration to (module A) during initialization.
The data is:
struct _data
{
int temp;
int velocity;
int time;
}
For example, (module A) should send 'temp' at first slot, then 'temp & velocity' at second slot, then 'time' at third slot .... etc
I am thinking about making making "configuration flags" structure:
struct _configuration
{
int temp_flag;
int time_flag;
int velocity_flag;
}
Then making an array of this structures:
struct _configuration arr[NUMBER_OF_SLOTS];
and configure using this array:
arr[0].temp_flag = 1;
arr[0].velocity_flag = 0;
arr[0].time_flag = 0;
arr[1].temp_flag = 1;
arr[1].velocity_flag = 1;
arr[1].time_flag = 0;
arr[2].temp_flag = 0;
arr[2].velocity_flag = 0;
arr[2].time_flag = 1;
.... etc
But I am not very happy with this approach ... does anyone has a better way or algorithm to do this task ?
Many thanks in advance
One of the many possible solutions is bitmasks (very popular in computer graphics). As you know, every number can be represented as sequence of 0 and 1, so they can be the flags that mean something. It's quite simple to use them in such way because we have bitwise operations. And there is no need to create some configuration structures.
const int USE_TEMP = 1 << 0; // 01
const int USE_VELOCITY = 1 << 1; // 010
const int USE_TIME = 1 << 2; // 0100
// ...
// you have 32 free-to-use bits
const int USE_ALL = 0111; // just for fun
struct _data {
int temp;
int velocity;
int time;
}
And it bring us to
int arr[NUMBER_OF_SLOTS];
arr[0] = USE_TEMP;
arr[1] = USE_TEMP | USE_VELOCITY;
arr[2] = USE_TIME;
Looks better, isn't it?
Checking values
When you need to check whether some of the parameters included in configuration, it's very simple
if( arr[i] & USE_TEMP ) {
// do smth with temp, it's included
}
or this way
int expected_flags = USE_TIME | USE_VELOCITY;
if( arr[i] & expected_flags == expected_flags ) {
// time and velocity enabled
}
or even declare special function (or scary macro) to check whether some parameters are in your config
bool check(int config, int flags) {
return config & flags == flags;
}
Changing configurations
What if you need to delete/add parameters?
int some_conf = USE_TEMP | USE_VELOCITY;
Simple way
// delete
if( check(some_conf, USE_VELOCITY) )
some_conf -= USE_VELOCITY; // <--- dangerous without if( )
// add
if( !check(some_conf, USE_TIME) )
some_conf += USE_TIME; // <--- dangerous without if( )
Safety way
// delete
some_conf &= ~USE_VELOCITY;
// add
some_conf |= USE_TIME;
I am watching a directory for file system events. Everything seems to work fine with one exception. When I create a file the first time, it spits out that it was created. Then I can remove it and it says it was removed. When I go to create the same file again, I get both a created and removed flag at the same time. I obviously am misunderstanding how the flags are being set when the callback is being called. What is happening here?
//
// main.c
// GoFSEvents
//
// Created by Kyle Cook on 8/22/13.
// Copyright (c) 2013 Kyle Cook. All rights reserved.
//
#include <CoreServices/CoreServices.h>
#include <stdio.h>
#include <string.h>
void eventCallback(FSEventStreamRef stream, void* callbackInfo, size_t numEvents, void* paths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) {
char **pathsList = paths;
for(int i = 0; i<numEvents; i++) {
uint32 flag = eventFlags[i];
uint32 created = kFSEventStreamEventFlagItemCreated;
uint32 removed = kFSEventStreamEventFlagItemRemoved;
if(flag & removed) {
printf("Item Removed: %s\n", pathsList[i]);
}
else if(flag & created) {
printf("Item Created: %s\n", pathsList[i]);
}
}
}
int main(int argc, const char * argv[])
{
CFStringRef mypath = CFSTR("/path/to/dir");
CFArrayRef paths = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL);
CFRunLoopRef loop = CFRunLoopGetMain();
FSEventStreamRef stream = FSEventStreamCreate(NULL, (FSEventStreamCallback)eventCallback, NULL, paths, kFSEventStreamEventIdSinceNow, 1.0, kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagNoDefer);
FSEventStreamScheduleWithRunLoop(stream, loop, kCFRunLoopDefaultMode);
FSEventStreamStart(stream);
CFRunLoopRun();
FSEventStreamStop(stream);
FSEventStreamInvalidate(stream);
FSEventStreamRelease(stream);
return 0;
}
As far as I can tell, you will have to look for either kFSEventStreamEventFlagItemRemoved or kFSEventStreamEventFlagItemCreated, and then use stat() or similar to check if the file was in fact added or deleted. The FSEvents documentation seems to hint as such.
It looks like the API is or'ing the events bits together... so really it's an OR of all the changes made since the FSEventsListener is created. Since that seems to be the case, another option might be to create a new FSEventListener each time (and use the coalesce timer option).
I did some Googling, but didn't find other examples of this problem or even apple sample code, but I didn't spend too long on it.
I have previously used the kqueue API: https://gist.github.com/nielsbot/5155671 (This gist is an obj-c wrapper around kqueue)
I changed your sample code to show all flags set for each FSEvent:
#include <CoreServices/CoreServices.h>
#include <stdio.h>
#include <string.h>
static int __count = 0 ;
void eventCallback(FSEventStreamRef stream, void* callbackInfo, size_t numEvents, void* paths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) {
char **pathsList = paths;
printf("callback #%u\n", ++__count ) ;
const char * flags[] = {
"MustScanSubDirs",
"UserDropped",
"KernelDropped",
"EventIdsWrapped",
"HistoryDone",
"RootChanged",
"Mount",
"Unmount",
"ItemCreated",
"ItemRemoved",
"ItemInodeMetaMod",
"ItemRenamed",
"ItemModified",
"ItemFinderInfoMod",
"ItemChangeOwner",
"ItemXattrMod",
"ItemIsFile",
"ItemIsDir",
"ItemIsSymlink",
"OwnEvent"
} ;
for(int i = 0; i<numEvents; i++)
{
printf("%u\n", i ) ;
printf("\tpath %s\n", pathsList[i]) ;
printf("\tflags: ") ;
long bit = 1 ;
for( int index=0, count = sizeof( flags ) / sizeof( flags[0]); index < count; ++index )
{
if ( ( eventFlags[i] & bit ) != 0 )
{
printf("%s ", flags[ index ] ) ;
}
bit <<= 1 ;
}
printf("\n") ;
}
FSEventStreamFlushSync( stream ) ;
}
int main(int argc, const char * argv[])
{
CFStringRef path = CFStringCreateWithCString( kCFAllocatorDefault, argv[1], kCFStringEncodingUTF8 ) ;
CFArrayRef paths = CFArrayCreate(NULL, (const void **)&path, 1, &kCFTypeArrayCallBacks );
if ( path ) { CFRelease( path ) ; }
CFRunLoopRef loop = CFRunLoopGetCurrent() ;
FSEventStreamRef stream = FSEventStreamCreate(NULL, (FSEventStreamCallback)eventCallback, NULL, paths, kFSEventStreamEventIdSinceNow, 0, kFSEventStreamCreateFlagFileEvents );
if ( paths ) { CFRelease( paths ) ; }
FSEventStreamScheduleWithRunLoop(stream, loop, kCFRunLoopDefaultMode);
FSEventStreamStart(stream);
CFRunLoopRun() ;
FSEventStreamStop(stream);
FSEventStreamInvalidate(stream);
FSEventStreamRelease(stream);
return 0;
}
If I had some enums like
typedef enum {
AN_TRISTATE_0,
AN_TRISTATE_1,
AN_NOTHING,
AN_MOTOR_1,
AN_MOTOR_2,
AN_MOTOR_3,
AN_SENSOR_1,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_func_t;
and
adc_pin_func_t a_particular_pin = ...
, would it be possible it check if the pin is part of a particular group, e.g pin is part of AN_MOTOR or part of AN_SENSOR, instead of having to check against each item in each possible group.
Or are there more efficient ways of doing this, other than using enums?
Thanks in advance
You could create masks for each of the groups:
typedef enum {
AN_TRISTATE_0 = 0x00001,
AN_TRISTATE_1 = 0x00002,
AN_TRISTATE_MASK = 0x0000f,
AN_NOTHING = 0x00010, // Should this be 0x00000 ?
AN_MOTOR_1 = 0x00100,
AN_MOTOR_2 = 0x00200,
AN_MOTOR_3 = 0x00400,
AN_MOTOR_MASK = 0x00f00,
AN_SENSOR_1 = 0x01000,
AN_SENSOR_2 = 0x02000,
AN_SENSOR_3 = 0x04000,
AN_SENSOR_4 = 0x08000,
AN_SENSOR_5 = 0x10000,
AN_SENSOR_MASK = 0xff000
} adc_pin_func_t;
And then simply test a group against the mask using the & operator:
if (a_particular_pin & AN_SENSOR_MASK)
{
// it's a sensor pin
}
else if (a_particular_pin & AN_MOTOR_MASK)
{
// it's a motor pin
}
EDIT: As others have suggested using a range, then you could probably create a macro for the test, which would allow you to change how the test is performed without the need to change the code (always a good thing):
#define IS_AN_SENSOR(x) (((x) & AN_SENSOR_MASK) != 0)
#define IS_AN_MOTOR(x) (((x) & AN_MOTOR_MASK) != 0)
// etc.
and then the test becomes:
if (IS_AN_SENSOR(a_particular_pin))
{
// it's a sensor pin
}
else if (IS_AN_MOTOR(a_particular_pin))
{
// it's a motor pin
}
// etc
If you then needed to change to using a range then only the macros need to change (and you'd obviously need to define the range min/max):
#define IS_AN_SENSOR(x) ((x) >= AN_SENSOR_START && (x) <= AN_SENSOR_END)
// etc
You are free to choose your enum values, so you could do something like this
typedef enum {
AN_TRISTATE_0 = 0x0001,
AN_TRISTATE_1 = 0x0002,
AN_NOTHING = 0x0000,
AN_MOTOR_1 = 0x0010,
AN_MOTOR_2 = 0x0020,
AN_MOTOR_3 = 0x0030,
AN_SENSOR_1 = 0x0100,
AN_SENSOR_2 = 0x0200,
AN_SENSOR_3, /*and so on*/
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_func_t;
Then you can compare bits to check categories. For example, a motor type is the only category that will have non-zero (AN_MOTOR_2 & 0x00F0)
You can do a
typedef enum {
AN_TRISTATE_START,
AN_TRISTATE_0 = AN_TRISTATE_START,
AN_TRISTATE_1,
AN_TRISTATE_END = AN_TRISTATE_1,
AN_NOTHING,
AN_MOTOR_START,
AN_MOTOR_1 = AN_MOTOR_START,
AN_MOTOR_2,
AN_MOTOR_3,
AN_MOTOR_END = AN_MOTOR_3,
AN_SENSOR_START,
AN_SENSOR_1 = AN_SENSOR_START,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5,
AN_SENSOR_END = AN_SENSOR_5
} adc_pin_func_t;
bool inline
is_sensor(int pin)
{
return AN_SENSOR_START <= pin
&& pin <= AN_SENSOR_END
}
and then in your code
if ( is_sensor(pin) )
{
/* body */
}
This way you don't have to care about masking particular values. May be useful if groups contain a lot of values.
You can give values to the enum in exponents of 2. Then you can simply use bitwise AND and OR masks. So you can assign values like 1,2,4,8,16,32... so on.
typedef enum {
AN_TRISTATE_0 = 1,
AN_TRISTATE_1 = 2,
AN_NOTHING = 4,
AN_MOTOR_1 = 8,
AN_MOTOR_2 = 16,
AN_MOTOR_3 = 32,
AN_SENSOR_1 = 64,
AN_SENSOR_2 = 128,
AN_SENSOR_3 = 256,
AN_SENSOR_4 = 512,
AN_SENSOR_5 = 1024
} adc_pin_func_t;
Then for checking with motor type, you can AND with (32+16+8) = 56. So pin & 56, if non zero will mean it is of motor type.
If you really like to have some modularity in your enum (the "hard coded" enum values are also a valid method), you can implement a struct with some OOP flavour. The design become more complicated, but the usage is still simple :
#include <stdio.h>
#include <string.h>
// Every enum will have its first value start at the value of the previous enum's last member PLUS ONE
#define OFFSET_ENUM_MOTOR ( sizeof(adc_pin_tristate_t) )
#define OFFSET_ENUM_SENSOR ( OFFSET_ENUM_MOTOR + sizeof(adc_pin_motor_t) )
///////////////////////////////////////////////////////////////////////////////
// Enum
typedef enum {
AN_TRISTATE_0,
AN_TRISTATE_1,
AN_NOTHING
} adc_pin_tristate_t;
typedef enum {
AN_MOTOR_1 = OFFSET_ENUM_MOTOR,
AN_MOTOR_2,
AN_MOTOR_3
} adc_pin_motor_t;
typedef enum {
AN_SENSOR_1 = OFFSET_ENUM_SENSOR,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_sensor_t;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Struct for abstraction
typedef struct adc_pin_func2_t{
// our "enum value"
unsigned int enum_id;
// return is the enum is a motor one
int(*isMotor)(struct adc_pin_func2_t*);
} adc_pin_func2_t;
// Struct
///////////////////////////////////////////////////////////////////////////////
// Member methods : return if the enum is a motor one
int
PinFunc_isMotor(
adc_pin_func2_t *This /* object */
)
{
return ( (This->enum_id>=OFFSET_ENUM_MOTOR) && (This->enum_id<OFFSET_ENUM_SENSOR) );
}
// Creation of the structure
// Initialization
static void
PinFunc_Init(
adc_pin_func2_t *This, /* output */
unsigned int identifier /* old enum identifier */
)
{
// copy members
This->enum_id = identifier;
//copy methods (do not forget to do it !)
This->isMotor = PinFunc_isMotor;
}
// Constructor
adc_pin_func2_t
PinFunc_Create(
unsigned int identifier /* old enum identifier */
)
{
adc_pin_func2_t This;
PinFunc_Init(&This, identifier);
return This;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
main()
{
adc_pin_func2_t pin = PinFunc_Create(AN_NOTHING);
printf("%d \n", pin );
printf("%d \n", pin.isMotor(&pin) );
adc_pin_func2_t pin2 = PinFunc_Create(AN_MOTOR_2);
printf("%d \n", pin2 );
printf("%d \n", pin2.isMotor(&pin2) );
}
The usage of members functions like pin.isMotor(&pin) isn't very elegant (we repeat pin), but it is a shortcoming of C, which is not an OOP language.
If you don't want to have to manually maintain non-overlapping values, then you can very nearly get it all handled for you automatically. The only thing you'll have to figure out is the maximum number of bits in a group:
#define PIN_GROUP_SHIFT 4
#define GET_PIN_GROUP(x) (adc_pin_group_t)((y) >> PIN_GROUP_SHIFT)
#define PIN_GROUP_START(x) XX_GROUP_##x = ((GROUP_##x << PIN_GROUP_SHIFT) - 1),
enum {
GROUP_TRISTATE,
GROUP_NOTHING,
GROUP_MOTOR,
GROUP_SENSOR
} adc_pin_group_t;
typedef enum {
PIN_GROUP_START(TRISTATE)
AN_TRISTATE_0,
AN_TRISTATE_1,
PIN_GROUP_START(NOTHING)
AN_NOTHING,
PIN_GROUP_START(MOTOR)
AN_MOTOR_1,
AN_MOTOR_2,
AN_MOTOR_3,
PIN_GROUP_START(SENSOR)
AN_SENSOR_1,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_func_t;
To determine the type of an entry in the enum, use GET_PIN_GROUP(x), and compare it to whichever value of the adc_pin_group_t enum. You can even switch on the result, if that's helpful.
However, that AN_NOTHING entry makes me wonder if your enum is meant to line up with specific values for each entry. are specific values associated with the pins, which you may not be able to assign arbitrarily. In that case you might need to try something complicated (which I haven't tested):
#define GET_PIN_VALUE(x) ((x) & ((1 << PIN_GROUP_SHIFT) - 1)
#define PIN_GROUP_START(x) \
WW_GROUP_##x, \
XX_GROUP_##x = (GROUP_##x << PIN_GROUP_SHIFT) \
+ GET_PIN_INDEX(WW_GROUP_##x) - 1,
Where you need to know the value that your original enum would have used, use GET_PIN_INDEX(x).