bool CMNGAnimation::Load(const char* filename, IFileSystem& fs) { this->~CMNGAnimation(); // open the file m_file = fs.Open(filename, IFileSystem::read); if (m_file == NULL) { return false; } // initialize MNG playback m_stream = mng_initialize(this, CB_Allocate, CB_Free, NULL); // set all of the callbacks mng_setcb_openstream(m_stream, CB_OpenStream); mng_setcb_closestream(m_stream, CB_CloseStream); mng_setcb_readdata(m_stream, CB_ReadData); mng_setcb_processheader(m_stream, CB_ProcessHeader); mng_setcb_gettickcount(m_stream, CB_GetTickCount); mng_setcb_getcanvasline(m_stream, CB_GetCanvasLine); mng_setcb_refresh(m_stream, CB_Refresh); mng_setcb_settimer(m_stream, CB_SetTimer); // do some reading if (mng_read(m_stream) != MNG_NOERROR) { return false; } return true; }
ILboolean iLoadMngInternal() { mng_handle mng; if (iCurImage == NULL) { ilSetError(IL_ILLEGAL_OPERATION); return IL_FALSE; } mng = mng_initialize(MNG_NULL, mymngalloc, mymngfree, MNG_NULL); if (mng == MNG_NULL) { ilSetError(IL_LIB_MNG_ERROR); return IL_FALSE; } // If .mng background is available, use it. mng_set_usebkgd(mng, MNG_TRUE); // Set the callbacks. mng_setcb_errorproc(mng, mymngerror); mng_setcb_openstream(mng, mymngopenstream); mng_setcb_closestream(mng, mymngclosestream); mng_setcb_readdata(mng, (mng_readdata)mymngreadstream); mng_setcb_gettickcount(mng, mymnggetticks); mng_setcb_settimer(mng, mymngsettimer); mng_setcb_processheader(mng, mymngprocessheader); mng_setcb_getcanvasline(mng, mymnggetcanvasline); mng_setcb_refresh(mng, mymngrefresh); mng_read(mng); mng_display(mng); return ilFixImage(); }
/** ** Load a MNG ** ** @param name Name of the MNG file */ int Mng::Load(const char *name) { mng_retcode myretcode; char buf[PATH_MAX]; LibraryFileName(name, buf, sizeof(buf)); this->name = new_strdup(buf); handle = mng_initialize(this, my_alloc, my_free, MNG_NULL); if (handle == MNG_NULL) { return -1; } mng_setcb_openstream(handle, my_openstream); mng_setcb_closestream(handle, my_closestream); mng_setcb_readdata(handle, my_readdata); mng_setcb_processheader(handle, my_processheader); mng_setcb_processmend(handle, my_processmend); mng_setcb_getcanvasline(handle, my_getcanvasline); mng_setcb_refresh(handle, my_refresh); mng_setcb_gettickcount(handle, my_gettickcount); mng_setcb_settimer(handle, my_settimer); mng_setcb_errorproc(handle, my_errorproc); mng_read(handle); if (surface && iteration != 0x7fffffff) { myretcode = mng_display(handle); } if (!surface || iteration == 0x7fffffff) { return -1; } return 0; }
/** ** Load a MNG ** ** @param name Name of the MNG file */ int Mng::Load(const std::string &name) { this->name = LibraryFileName(name.c_str()); handle = mng_initialize(this, my_alloc, my_free, MNG_NULL); if (handle == MNG_NULL) { return -1; } mng_setcb_openstream(handle, my_openstream); mng_setcb_closestream(handle, my_closestream); mng_setcb_readdata(handle, my_readdata); mng_setcb_processheader(handle, my_processheader); mng_setcb_processmend(handle, my_processmend); mng_setcb_getcanvasline(handle, my_getcanvasline); mng_setcb_refresh(handle, my_refresh); mng_setcb_gettickcount(handle, my_gettickcount); mng_setcb_settimer(handle, my_settimer); mng_setcb_errorproc(handle, my_errorproc); mng_read(handle); if (surface && iteration != 0x7fffffff) { mng_display(handle); } if (!surface || iteration == 0x7fffffff) { return -1; } return 0; }
static gboolean gtk_mng_view_init_libmng (GtkMngView * mng_view) { FUNCTION_ENTRY(); GtkWidget * widget; g_return_val_if_fail (IS_GTK_MNG_VIEW (mng_view), FALSE); if (mng_view->MNG_handle) mng_cleanup (&mng_view->MNG_handle); mng_view->MNG_handle = mng_initialize (mng_view, mng_malloc_callback, mng_free_callback, MNG_NULL); if (mng_view->MNG_handle == MNG_NULL) { FUNCTION_EXIT(); return FALSE; } mng_set_storechunks(mng_view->MNG_handle, MNG_TRUE); //mng_set_dfltimggamma(mng_view->MNG_handle, 5); //mng_set_displaygamma(mng_view->MNG_handle, 4); if (mng_setcb_openstream (mng_view->MNG_handle, mng_open_stream_callback) != MNG_NOERROR || mng_setcb_closestream (mng_view->MNG_handle, mng_close_stream_callback) != MNG_NOERROR || mng_setcb_readdata (mng_view->MNG_handle, mng_read_data_callback) != MNG_NOERROR || mng_setcb_processheader (mng_view->MNG_handle, mng_process_header_callback) != MNG_NOERROR || mng_setcb_processmend (mng_view->MNG_handle, mng_process_mend_callback) != MNG_NOERROR || mng_setcb_processterm (mng_view->MNG_handle, mng_process_term_callback) != MNG_NOERROR || mng_setcb_settimer (mng_view->MNG_handle, mng_set_timer_callback) != MNG_NOERROR || mng_setcb_gettickcount (mng_view->MNG_handle, mng_get_tickcount_callback) != MNG_NOERROR || mng_setcb_getcanvasline (mng_view->MNG_handle, mng_get_canvas_line_callback) != MNG_NOERROR || mng_setcb_getalphaline (mng_view->MNG_handle, mng_get_alpha_line_callback) != MNG_NOERROR || mng_setcb_refresh (mng_view->MNG_handle, mng_refresh_callback) != MNG_NOERROR) { mng_cleanup (&mng_view->MNG_handle); FUNCTION_EXIT(); return FALSE; } //mng_set_suspensionmode(mng_view->MNG_handle, MNG_TRUE); mng_set_canvasstyle (mng_view->MNG_handle, MNG_CANVAS_RGB8_A8); widget = GTK_WIDGET (mng_view); if (!GTK_WIDGET_REALIZED (widget)) gtk_widget_realize (widget); mng_set_bgcolor (mng_view->MNG_handle, widget->style->bg[GTK_STATE_NORMAL].red, widget->style->bg[GTK_STATE_NORMAL].green, widget->style->bg[GTK_STATE_NORMAL].blue); FUNCTION_EXIT(); return TRUE; }
//--------------------------------------------------------------------------- bool __fastcall TMainForm::DumpTree( void ) { mng_handle hMNG; // let's initialize the library hMNG = mng_initialize( (mng_ptr)this, Alloc, Free, NULL ); if( !hMNG ) // did that work out ? { MNGError( hMNG, "Cannot initialize libmng." ); mng_cleanup( &hMNG ); // Always cleanup the library MsgBoxStop( "Bye!" ); Application->Terminate(); // Exit now } // setup callbacks if( (mng_setcb_openstream ( hMNG, OpenStream ) != 0) || (mng_setcb_closestream ( hMNG, CloseStream ) != 0) || (mng_setcb_processheader( hMNG,ProcessHeader ) != 0) || (mng_setcb_readdata ( hMNG, FileReadData ) != 0) ) { MNGError( hMNG, "Cannot set callbacks for libmng."); mng_cleanup( &hMNG ); // Always cleanup the library MsgBoxStop( "Bye!" ); Application->Terminate(); // Exit now } else { // read the file into memory if( mng_read( hMNG ) != 0 ) { // Because we read the whole file in first, // here is where bad input files first choke ! MNGError( hMNG, "Cannot read the file." ); mng_cleanup( &hMNG ); // Always cleanup the library return false; } else { // run through the chunk list if( mng_iterate_chunks( hMNG, 0, IterateChunks ) != 0 ) { MNGError( hMNG, "Error Getting Chunk info!" ); mng_cleanup( &hMNG ); // Always cleanup the library return false; // Errors may occur with bad chunk data } } } mng_cleanup( &hMNG ); // Always cleanup the library return true; }
// return 1 if okay static int my_init_mng(PluginInstance *This) { mng_retcode rv; int err; This->mng = mng_initialize((mng_ptr)This,memallocfunc,memfreefunc,NULL); //(mng_memalloc) (mng_memfree) #ifdef MNGPLG_CMS init_color_management(This); #endif err=0; rv=mng_setcb_openstream (This->mng, callback_openstream ); if(rv) err++; rv=mng_setcb_closestream (This->mng, callback_closestream ); if(rv) err++; rv=mng_setcb_readdata (This->mng, callback_readdata ); if(rv) err++; rv=mng_setcb_processheader (This->mng, callback_processheader); if(rv) err++; rv=mng_setcb_getcanvasline (This->mng, callback_getcanvasline); if(rv) err++; rv=mng_setcb_refresh (This->mng, callback_refresh ); if(rv) err++; rv=mng_setcb_gettickcount (This->mng, callback_gettickcount ); if(rv) err++; rv=mng_setcb_settimer (This->mng, callback_settimer ); if(rv) err++; rv=mng_setcb_processtext (This->mng, callback_processtext ); if(rv) err++; #ifdef MNGPLG_TRACE rv=mng_setcb_traceproc (This->mng, callback_traceproc ); if(rv) err++; #endif if(err) { warn(This,"Error setting libmng callback functions"); return 0; } rv= mng_set_suspensionmode (This->mng,MNG_TRUE); if(rv) { warn(This,"Error setting suspension mode"); return 0; } // if the web page author provided a bgcolor, use it if(This->force_bgcolor) { rv=mng_set_bgcolor (This->mng, This->bg_r, This->bg_g, This->bg_b); } #ifdef MNGPLG_TRACE fprintf(tracefile,"initial readdisplay\n"); #endif handle_read_error(This, mng_readdisplay(This->mng) ); return 1; }
bool ImageJngFile::Load (uint8 *iBuffer, size_t iSize) { mng_retcode retcode; const int magicSize = 8; const char magicMNG[] = "\x8aMNG\x0d\x0a\x1a\x0a"; const char magicJNG[] = "\x8bJNG\x0d\x0a\x1a\x0a"; // check for magic JNG/MNG bytes. If not correct, we can skip // messing around w/ libmng entirely. if ((iSize < 8) || ((memcmp ((void*)iBuffer, (void*)&magicMNG, magicSize)) && (memcmp ((void*)iBuffer, (void*)&magicJNG, magicSize)))) { return false; } handle = mng_initialize (mng_ptr(this), cb_alloc, cb_free, MNG_NULL); if (!handle) { Report (object_reg, CS_REPORTER_SEVERITY_WARNING, "failed to initialize libmng"); return false; } buffer = iBuffer; bufptr = buffer; bufferSize = iSize; if ((mng_setcb_openstream (handle, cb_openstream) != MNG_NOERROR) || (mng_setcb_closestream (handle, cb_closestream) != MNG_NOERROR) || (mng_setcb_readdata (handle, cb_readdata) != MNG_NOERROR) || (mng_setcb_processheader(handle, cb_processheader) != MNG_NOERROR) || (mng_setcb_getcanvasline(handle, cb_getcanvasline) != MNG_NOERROR) || (mng_setcb_refresh(handle, cb_imagerefresh) != MNG_NOERROR) || (mng_setcb_gettickcount(handle, cb_gettickcount) != MNG_NOERROR) || (mng_setcb_settimer(handle, cb_settimer) != MNG_NOERROR)) { ReportLibmngError (object_reg, handle, "failed to set libmng callbacks"); mng_cleanup (&handle); return false; } retcode = mng_read (handle); if (retcode != MNG_NOERROR) { if (retcode != MNG_INVALIDSIG) // maybe its just not an jng/mng... ReportLibmngError (object_reg, handle, "failed to read data"); mng_cleanup (&handle); return false; } // Don't read PNGs if (mng_get_sigtype (handle) == mng_it_png) { delete[] NewImage; mng_cleanup (&handle); return false; } // Even on still images, libmng issues timer requests. // so, as long as the requests are 'immediate' we continue // displaying. If a delay is requested we end loading. timer = 2; retcode = mng_display (handle); while ((retcode == MNG_NEEDTIMERWAIT) && (timer <= 1)) { retcode = mng_display_resume (handle); } if ((retcode != MNG_NOERROR) && (retcode != MNG_NEEDTIMERWAIT)) { ReportLibmngError (object_reg, handle, "failed to display data"); mng_cleanup (&handle); return false; } doWait = (retcode == MNG_NEEDTIMERWAIT); animated = doWait; if (NewImage) { csRGBpixel *rgbImage = csPackRGBA::CopyUnpackRGBAtoRGBpixel (NewImage, Width*Height); ConvertFromRGBA (rgbImage); // Subsequent images may contain alpha, so don't check if (!doWait) CheckAlpha(); } if (mng_get_sigtype (handle) != mng_it_mng) { delete[] NewImage; NewImage = 0; mng_cleanup (&handle); handle = 0; } return true; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { mng_handle hmng = NULL; if (handle != NULL) { try { // allocate our stream data structure mngstuff *mymng = (mngstuff *)data; // set up the mng decoder for our stream hmng = mng_initialize(mymng, mymngalloc, mymngfree, MNG_NULL); if (hmng == MNG_NULL) { throw "could not initialize libmng"; } // set the colorprofile, lcms uses this mng_set_srgb(hmng, MNG_TRUE ); // set white as background color WORD wRed, wGreen, wBlue; wRed = wGreen = wBlue = (255 << 8) + 255; mng_set_bgcolor(hmng, wRed, wGreen, wBlue); // if PNG Background is available, use it mng_set_usebkgd(hmng, MNG_TRUE ); // no need to store chunks mng_set_storechunks(hmng, MNG_FALSE); // no need to wait: straight reading mng_set_suspensionmode(hmng, MNG_FALSE); // set the callbacks mng_setcb_errorproc(hmng, mymngerror); mng_setcb_openstream(hmng, mymngopenstream); mng_setcb_closestream(hmng, mymngclosestream); mng_setcb_readdata(hmng, mymngreadstream); mng_setcb_processheader(hmng, mymngprocessheader); mng_setcb_getcanvasline(hmng, mymnggetcanvasline); mng_setcb_refresh(hmng, mymngrefresh); mng_setcb_gettickcount(hmng, mymnggetticks); mng_setcb_settimer(hmng, mymngsettimer); // read in the bitmap mng_readdisplay(hmng); // read all bitmaps int retval = MNG_NOERROR; mng_datap pData = (mng_datap)hmng; while(pData->bReading) { retval = mng_display_resume(hmng); if((retval == MNG_NEEDTIMERWAIT) || (retval == MNG_FUNCTIONINVALID)) break; } // temp store the newly created bitmap FIBITMAP *bitmap = mymng->bitmap; // cleanup and return the temp stored bitmap mng_cleanup(&hmng); return bitmap; } catch (const char *message) { FIBITMAP *bitmap = ((mngstuff *)mng_get_userdata(hmng))->bitmap; if(bitmap) { FreeImage_Unload(bitmap); } mng_cleanup(&hmng); FreeImage_OutputMessageProc(s_format_id, message); } } return NULL; }
/** * \brief MPlayer callback: Open MNG stream. * \param[in] demuxer demuxer structure * \return demuxer structure on success, \p NULL on error */ static demuxer_t * demux_mng_open(demuxer_t * demuxer) { mng_priv_t * mng_priv; mng_handle h_mng; mng_retcode mng_ret; sh_video_t * sh_video; // create private data structure mng_priv = calloc(1, sizeof(mng_priv_t)); //stream pointer into private data mng_priv->stream = demuxer->stream; // initialize MNG image instance h_mng = mng_initialize((mng_ptr)mng_priv, demux_mng_alloc, demux_mng_free, MNG_NULL); if (!h_mng) { mp_msg(MSGT_DEMUX, MSGL_ERR, "demux_mng: could not initialize MNG image instance\n"); free(mng_priv); return NULL; } // MNG image handle into private data mng_priv->h_mng = h_mng; // set required MNG callbacks if (mng_setcb_openstream(h_mng, demux_mng_openstream) || mng_setcb_closestream(h_mng, demux_mng_closestream) || mng_setcb_readdata(h_mng, demux_mng_readdata) || mng_setcb_processheader(h_mng, demux_mng_processheader) || mng_setcb_getcanvasline(h_mng, demux_mng_getcanvasline) || mng_setcb_refresh(h_mng, demux_mng_refresh) || mng_setcb_gettickcount(h_mng, demux_mng_gettickcount) || mng_setcb_settimer(h_mng, demux_mng_settimer) || mng_set_canvasstyle(h_mng, MNG_CANVAS_RGBA8)) { mp_msg(MSGT_DEMUX, MSGL_ERR, "demux_mng: could not set MNG callbacks\n"); mng_cleanup(&h_mng); free(mng_priv); return NULL; } // start reading MNG data mng_ret = mng_read(h_mng); if (mng_ret) { mp_msg(MSGT_DEMUX, MSGL_ERR, "demux_mng: could not start reading MNG data: " "mng_retcode %d\n", mng_ret); mng_cleanup(&h_mng); free(mng_priv); return NULL; } // check that MNG header is processed now if (!mng_priv->header_processed) { mp_msg(MSGT_DEMUX, MSGL_ERR, "demux_mng: internal error: header not processed\n"); mng_cleanup(&h_mng); free(mng_priv); return NULL; } // create a new video stream header sh_video = new_sh_video(demuxer, 0); // Make sure the demuxer knows about the new video stream header // (even though new_sh_video() ought to take care of it). // (Thanks to demux_gif.c for this.) demuxer->video->sh = sh_video; // Make sure that the video demuxer stream header knows about its // parent video demuxer stream (this is getting wacky), or else // video_read_properties() will choke. // (Thanks to demux_gif.c for this.) sh_video->ds = demuxer->video; // set format of pixels in video packets sh_video->format = mmioFOURCC(32, 'B', 'G', 'R'); // set framerate to some value (MNG does not have a fixed framerate) sh_video->fps = 5.0f; sh_video->frametime = 1.0f / sh_video->fps; // set video frame parameters sh_video->bih = malloc(sizeof(*sh_video->bih)); sh_video->bih->biCompression = sh_video->format; sh_video->bih->biWidth = mng_priv->width; sh_video->bih->biHeight = mng_priv->height; sh_video->bih->biBitCount = 32; sh_video->bih->biPlanes = 1; // Set start time to something > 0. // - This is required for the variable frame time mechanism // (GIF, MATROSKA, MNG) in video.c to work for the first frame. sh_video->ds->pts = MNG_START_PTS; // set private data in demuxer and return demuxer demuxer->priv = mng_priv; return demuxer; }
static bool sReadMNG(Stream &stream, GBitmap *bitmap) { PROFILE_SCOPE(sReadMNG); mngstuff mnginfo; dMemset(&mnginfo, 0, sizeof(mngstuff)); mng_handle mng = mng_initialize(&mnginfo, mngMallocFn, mngFreeFn, MNG_NULL); if(mng == NULL) return false; // setup the callbacks mng_setcb_errorproc(mng, mngFatalErrorFn); mng_setcb_openstream(mng, mngOpenDataFn); mng_setcb_closestream(mng, mngCloseDataFn); mng_setcb_readdata(mng, mngReadDataFn); mng_setcb_processheader(mng, mngProcessHeaderFn); mng_setcb_getcanvasline(mng, mngCanvasLineFn); mng_setcb_refresh(mng, mngRefreshFn); mng_setcb_gettickcount(mng, mngGetTicksFn); mng_setcb_settimer(mng, mngSetTimerFn); mnginfo.image = bitmap; mnginfo.stream = &stream; mng_read(mng); mng_display(mng); // hacks :( // libmng doesn't support returning data in gray/gray alpha format, // so we grab as RGB/RGBA and just cut off the g and b mng_uint8 colorType = mng_get_colortype(mng); switch(colorType) { case MNG_COLORTYPE_GRAY: case MNG_COLORTYPE_JPEGGRAY: { GBitmap temp(*bitmap); bitmap->deleteImage(); bitmap->allocateBitmap(temp.getWidth(), temp.getHeight(), false, GFXFormatA8); // force getColor to read in in the same color value for each channel // since the gray colortype has the real alpha in the first channel temp.setFormat( GFXFormatA8 ); ColorI color; for(U32 row = 0; row < bitmap->getHeight(); row++) { for(U32 col = 0; col < bitmap->getWidth(); col++) { temp.getColor(col, row, color); bitmap->setColor(col, row, color); } } } break; } mng_cleanup(&mng); // Check this bitmap for transparency bitmap->checkForTransparency(); return true; }
int main(int argc, char *argv[]) { int fbdev,c,option_index; unsigned int alpha; struct fb_var_screeninfo var; /* Check which console we're running on */ init_consoles(); /* allocate our stream data structure */ mng = (mngstuff *) calloc(1, sizeof(*mng)); if (mng == NULL) { fprintf(stderr, "could not allocate stream structure.\n"); exit(0); } alpha = 100; mng->alpha = 100; mng->fbx = 15; mng->fby = 15; mng->background = NULL; while (1) { static struct option long_options[] = { {"help", 0, 0, 'h'}, {"verbose", 0, 0, 'v'}, {"alpha", 1, 0, 'a'}, {"buffered", 0, 0, 'b'}, {"signal", 0, 0, 's'}, {"delta", 0, 0, 'd'}, {"position", 0, 0, 'p'}, {"version", 0, 0, 'V'}, {"start-console",0,0,'S'}, {"console",1,0,'c'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "a:x:y:bh?vsd:pVSc:", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': alpha = atoi(optarg); if (alpha > 100) alpha = 100; mng->alpha = alpha; break; case 'x': mng->fbx = atoi(optarg); break; case 'y': mng->fby = atoi(optarg); break; case 'd': delta = atoi(optarg); break; case '?': case 'h': usage(argv[0]); exit(0); case 'v': verbose = 1; break; case 's': waitsignal = 1; break; case 'b': buffered = 1; break; case 'p': dynpos = 1; break; case 'V': version(); exit(0); case 'c': start_console=atoi(optarg); case 'S': sconly=1; break; default: break; } } if (optind >= argc) { printf("Which files do you want to play?\n"); exit(0); } //init_consoles(); /* Initialize framebuffer */ fbdev = open("/dev/fb0", O_RDWR); if (fbdev < 0) { fprintf(stderr, "error while opening framebuffer.\n"); exit(fbdev); } ioctl(fbdev, FBIOGET_VSCREENINFO, &var); mng->fbwidth = var.xres; mng->fbheight = var.yres; mng->fbbpp = var.bits_per_pixel; mng->display = mmap(NULL, var.xres * var.yres * (var.bits_per_pixel >> 3), PROT_WRITE | PROT_READ, MAP_SHARED, fbdev, 0); /* arrange to call the shutdown routine before we exit */ atexit(&cleanup); while (optind < argc) { // leftover arguements are filenames. mng->filename = argv[optind++]; /* set up the mng decoder for our stream */ mng->mng = mng_initialize(mng, mngalloc, mngfree, MNG_NULL); if (mng->mng == MNG_NULL) { fprintf(stderr, "could not initialize libmng.\n"); exit(1); } /* set the callbacks */ mng_setcb_errorproc(mng->mng, mngerror); mng_setcb_openstream(mng->mng, mngopenstream); mng_setcb_closestream(mng->mng, mngclosestream); mng_setcb_readdata(mng->mng, mngreadstream); mng_setcb_gettickcount(mng->mng, mnggetticks); mng_setcb_settimer(mng->mng, mngsettimer); mng_setcb_processheader(mng->mng, mngprocessheader); mng_setcb_getcanvasline(mng->mng, mnggetcanvasline); mng_setcb_refresh(mng->mng, mngrefresh); /* FIXME: should check for errors here */ signal(SIGINT, sigint_handler); signal(SIGTERM, sigterm_handler); mng_readdisplay(mng->mng); /* loop though the frames */ while (mng->delay && run) { mdelay(mng->delay); mng->delay = 0; mng_display_resume(mng->mng); if (run == 2) { if (mng->alpha == 0) run = 0; mng->alpha -= delta; if (mng->alpha < 0) mng->alpha = 0; } } if (waitsignal && optind < argc) { signal(SIGUSR1, sigusr1_handler); run = 1; while (run) { sleep(2); } } memset(mng->copybuffer, 0, 4 * mng->width * mng->height); run = 1; mng->alpha = alpha; if (optind == argc) { /* last file */ restore_area(); } } /* cleanup and quit */ return mngquit(mng->mng); }